"""
配置面板 - 左侧配置区域组件
包含区域框选、交易密码、运行时间等配置功能
"""

import sys
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, 
                            QLineEdit, QPushButton, QGroupBox, QListWidget,
                            QListWidgetItem, QTimeEdit, QCheckBox, QSpinBox,
                            QTextEdit, QSplitter, QMessageBox, QComboBox)
from PyQt5.QtCore import Qt, QTime, pyqtSignal, QTimer
from PyQt5.QtGui import QFont, QIcon
from datetime import datetime, time
import logging

# 🔥 新增：数据库管理
from database.market_database import MarketDatabase

# 🔥 新增：持仓数据获取
from broker_account_scanner import BrokerAccountScanner
# 🔥 修复：移除直接导入，改为条件导入避免启动错误

from gui.area_selector import AreaSelectorDialog, AreaPreview


class ConfigPanel(QWidget):
    """配置面板"""
    
    # 信号定义
    config_changed = pyqtSignal(str, object)  # 配置变更信号
    start_monitoring = pyqtSignal()  # 开始监控信号
    stop_monitoring = pyqtSignal()   # 停止监控信号
    always_on_top_changed = pyqtSignal(bool)  # 窗口置顶状态变更信号
    trading_signal = pyqtSignal(str, dict)  # 交易信号 (action, data)
    
    def __init__(self, config_manager, parent=None):
        super().__init__(parent)
        self.config_manager = config_manager
        self.logger = logging.getLogger(__name__)
        
        # 当前监控状态
        self.is_monitoring = False
        
        # 交易防重复机制 - 记录最近执行的交易
        self.recent_trades = {}  # 格式: {股票代码: {'timestamp': 时间戳, 'action': 动作, 'position_diff': 仓位变化}}
        self.trade_cooldown = 30  # 🧪 测试设置：3秒冷却期
        
        # 🔥 防抖机制 - 防止快速连续触发相同交易
        self.trading_debounce = {}  # 格式: {股票代码: {'timestamp': 时间戳, 'signal_hash': 信号哈希}}
        self.debounce_time = 30  # 🧪 测试设置：3秒防抖
        
        # 🔥 持仓缓存机制 - 避免频繁调用API
        self.cached_positions = {}  # 格式: {股票代码: {'position_ratio': 仓位比例, 'market_price': 市价, 'quantity': 数量, 'timestamp': 缓存时间}}
        self.position_cache_time = 30  # 🔧 恢复30秒缓存，但交易后会立即清除
        self.initial_positions_loaded = False  # 标记是否已加载初始持仓
        
        # 🔥 新增：交易失败惩罚机制
        self.failed_trades = {}  # 格式: {股票代码: {'count': 连续失败次数, 'last_failure': 时间戳, 'reason': 失败原因}}
        self.failure_penalty_time = 180  # 连续失败后的惩罚冷却期：30分钟
        
        # 🔥 初始化数据库（启动时不清空，清空改为开始监控时）
        try:
            self.market_db = MarketDatabase()
            self.logger.info("✅ 市场数据库初始化成功")
            
            # 🔥 程序启动时查询资产用于显示（不清空数据库）
            self._query_account_assets_for_display()
            
        except Exception as e:
            self.logger.error(f"❌ 数据库初始化失败: {e}")
            self.market_db = None
        
        # 交易信号收集机制 - 用于批量处理多笔交易
        self.current_trading_signals = []  # 本轮OCR的所有交易信号
        
        # 初始化定时器用于实时更新账户资产
        from PyQt5.QtCore import QTimer
        self.account_update_timer = QTimer()
        self.account_update_timer.timeout.connect(self.update_current_account_funds)
        self.account_update_timer.setInterval(60000)  # 60秒（1分钟）更新一次
        
        # 记录最后更新时间
        self.last_funds_update_time = None
        
        self.setup_ui()
        self.load_config()
        self.connect_signals()
        
        # 🔥 在信号连接完成后恢复保存的选择
        self._restore_pending_selections()
    
    def _restore_pending_selections(self):
        """在信号连接完成后恢复保存的券商和账户选择"""
        try:
            # 恢复券商选择
            if hasattr(self, '_pending_broker_selection') and self._pending_broker_selection:
                selected_broker = self._pending_broker_selection
                
                # 临时断开信号避免干扰
                try:
                    self.broker_combo.currentIndexChanged.disconnect(self.on_broker_changed)
                    signal_disconnected = True
                except:
                    signal_disconnected = False
                
                success = self.select_broker_by_name(selected_broker)
                self.logger.info(f"🔧 尝试恢复券商选择: {selected_broker} {'✅成功' if success else '❌失败'}")
                
                # 手动刷新对应券商的账户（避免信号触发）
                if success:
                    self.refresh_accounts()
                
                # 重新连接信号
                if signal_disconnected:
                    self.broker_combo.currentIndexChanged.connect(self.on_broker_changed)
            
            # 恢复账户选择
            if hasattr(self, '_pending_account_selection') and self._pending_account_selection:
                selected_acc_id = self._pending_account_selection
                
                # 临时断开信号避免干扰
                try:
                    self.account_combo.currentIndexChanged.disconnect(self.on_account_changed)
                    signal_disconnected = True
                except:
                    signal_disconnected = False
                
                success = self.select_account_by_acc_id(selected_acc_id)
                self.logger.info(f"🔧 尝试恢复账户选择: {selected_acc_id} {'✅成功' if success else '❌失败'}")
                
                # 重新连接信号
                if signal_disconnected:
                    self.account_combo.currentIndexChanged.connect(self.on_account_changed)
                
                # 🔥 如果账户选择失败，记录当前状态用于调试
                if not success:
                    current_broker = self.get_current_broker()
                    current_acc_id = self.get_current_acc_id()
                    self.logger.warning(f"⚠️ 账户选择失败！ 期望: 券商={self._pending_broker_selection}, 账户={selected_acc_id}")
                    self.logger.warning(f"⚠️ 当前状态: 券商={current_broker}, 账户={current_acc_id}")
                    
                    # 检查当前券商的可用账户
                    account_count = self.account_combo.count()
                    self.logger.info(f"🔍 当前券商 '{current_broker}' 的可用账户数量: {account_count}")
                    for i in range(account_count):
                        account_data = self.account_combo.itemData(i)
                        if account_data:
                            acc_id = account_data.get('acc_id', 'N/A')
                            uni_card_num = account_data.get('uni_card_num', 'N/A')
                            self.logger.info(f"   账户{i+1}: acc_id={acc_id}, uni_card_num={uni_card_num}")
                else:
                    # 成功恢复账户选择后，手动触发账户信息更新
                    current_data = self.account_combo.currentData()
                    self.update_account_info(current_data)
            
            # 清理临时变量
            if hasattr(self, '_pending_broker_selection'):
                delattr(self, '_pending_broker_selection')
            if hasattr(self, '_pending_account_selection'):
                delattr(self, '_pending_account_selection')
                
        except Exception as e:
            self.logger.error(f"恢复保存的选择失败: {e}")
    
    def _query_account_assets_for_display(self):
        """程序启动时查询账户资产用于显示（不作为基准，不清空数据库）"""
        try:
            self.logger.info("🔍 程序启动 - 查询账户资产用于显示...")
            
            # 创建富途账户扫描器
            scanner = BrokerAccountScanner(self.config_manager)
            
            # 获取交易密码
            trading_password = self.config_manager.get('trading.password', '')
            if not trading_password:
                self.logger.warning("⚠️ 未设置交易密码，可能无法获取完整账户信息")
            
            # 从配置文件读取账户信息
            selected_acc_id = self.config_manager.get('trading.selected_acc_id')
            selected_broker = self.config_manager.get('trading.selected_broker')
            
            if not selected_acc_id or not selected_broker:
                self.logger.info("💰 未选择交易账户，跳过资产查询")
                self.logger.info(f"🔍 配置状态: selected_acc_id={selected_acc_id}, selected_broker={selected_broker}")
                return
            
            # 构造账户信息对象（同_initialize_position_baseline的逻辑）
            if 'Moomoo US' in selected_broker or 'US' in selected_broker:
                market_info = {
                    'market': 'US',  # TrdMarket.US
                    'market_name': '美股',
                    'trd_env': 'REAL',  # TrdEnv.REAL
                    'broker_firm': 'FUTUINC'  # SecurityFirm.FUTUINC
                }
            elif 'FUTU HK' in selected_broker or 'HK' in selected_broker:
                market_info = {
                    'market': 'HK',  # TrdMarket.HK
                    'market_name': '港股',
                    'trd_env': 'REAL',  # TrdEnv.REAL
                    'broker_firm': 'FUTUSECURITIES'  # SecurityFirm.FUTUSECURITIES
                }
            else:
                self.logger.error(f"❌ 不支持的券商类型: {selected_broker}")
                return
            
            selected_account = {
                'acc_id': selected_acc_id,
                'broker_name': selected_broker,
                'uni_card_num': '',
                'market': market_info['market'],
                'market_name': market_info['market_name'], 
                'trd_env': market_info['trd_env'],
                'broker_firm': market_info['broker_firm']
            }
            
            self.logger.info(f"🔧 构造账户信息: 券商={selected_broker}, 市场={market_info['market_name']}")
            
            # 查询账户资产
            fund_result = scanner.get_account_funds(selected_account, trading_password)
            if fund_result.get('success'):
                total_assets = fund_result.get('total_assets', 0)
                currency = fund_result.get('currency', 'USD')
                self.logger.info(f"💰 当前账户资产: {total_assets:.2f} {currency}")
            else:
                self.logger.warning(f"⚠️ 获取账户资产失败: {fund_result.get('error', '未知错误')}")
                
        except Exception as e:
            self.logger.error(f"❌ 查询账户资产失败: {e}")
    
    def _initialize_position_baseline(self):
        """开始监控时清空数据库并获取持仓数据作为基准"""
        try:
            # 🔥 先清空数据库历史数据
            self.logger.info("🧹 开始监控 - 清空数据库历史数据...")
            self.market_db.clear_baseline_data()
            self.market_db.clear_ocr_history()
            
            # 🔥 同时清空配置文件中的历史市场数据
            self.config_manager.set('market.previous_data', [])
            self.config_manager.auto_save()
            self.logger.info("🧹 数据库和配置文件历史数据已清空")
            
            self.logger.info("🔍 开始获取持仓数据作为初始基准...")
            
            # 创建富途账户扫描器
            scanner = BrokerAccountScanner(self.config_manager)
            
            # 获取交易密码
            trading_password = self.config_manager.get('trading.password', '')
            if not trading_password:
                self.logger.warning("⚠️ 未设置交易密码，可能无法获取完整持仓信息")
            
            # 🔧 修复：从正确的配置键读取账户信息
            selected_acc_id = self.config_manager.get('trading.selected_acc_id')
            selected_broker = self.config_manager.get('trading.selected_broker')
            
            if not selected_acc_id or not selected_broker:
                self.logger.warning("⚠️ 未选择交易账户，跳过持仓基准初始化")
                self.logger.info(f"🔍 配置状态: selected_acc_id={selected_acc_id}, selected_broker={selected_broker}")
                return
            
            # 🔧 构造完整的账户信息对象
            # 根据券商名称确定市场类型、交易环境和券商类型
            if 'Moomoo US' in selected_broker or 'US' in selected_broker:
                market_info = {
                    'market': 'US',  # TrdMarket.US
                    'market_name': '美股',
                    'trd_env': 'REAL',  # TrdEnv.REAL 真实环境
                    'broker_firm': 'FUTUINC'  # SecurityFirm.FUTUINC Moomoo US
                }
            elif 'FUTU HK' in selected_broker or 'HK' in selected_broker:
                market_info = {
                    'market': 'HK',  # TrdMarket.HK
                    'market_name': '港股',
                    'trd_env': 'REAL',  # TrdEnv.REAL 真实环境
                    'broker_firm': 'FUTUSECURITIES'  # SecurityFirm.FUTUSECURITIES 富途证券
                }
            else:
                # 默认港股
                market_info = {
                    'market': 'HK',  # TrdMarket.HK
                    'market_name': '港股',
                    'trd_env': 'REAL',  # TrdEnv.REAL
                    'broker_firm': 'FUTUSECURITIES'  # SecurityFirm.FUTUSECURITIES 默认富途证券
                }
            
            selected_account = {
                'acc_id': selected_acc_id,
                'broker_name': selected_broker,
                'uni_card_num': selected_acc_id,  # 兼容字段
                **market_info  # 展开市场信息
            }
            
            self.logger.info(f"🔧 构造账户信息: 券商={selected_broker}, 市场={market_info['market_name']}, broker_firm={market_info['broker_firm']}")
            
            self.logger.info(f"🎯 获取账户持仓: {selected_account.get('acc_id', 'N/A')}")
            
            # 查询持仓数据
            position_result = scanner.get_account_positions(selected_account, trading_password)
            
            if position_result['status'] == 'success':
                positions = position_result['positions']
                total_count = position_result['total_positions']
                
                if total_count > 0:
                    self.logger.info(f"✅ 获取到 {total_count} 个持仓")
                    
                    # 获取账户总资产用于计算仓位比例
                    fund_result = scanner.get_account_funds(selected_account, trading_password)
                    total_assets = 0.0
                    
                    if fund_result['status'] == 'success':
                        total_assets = fund_result['total_assets']
                        currency = fund_result.get('currency', 'USD')
                        market_type = fund_result.get('market_type', '')
                        conversion_rate = fund_result.get('conversion_rate', 1.0)
                        original_hkd = fund_result.get('original_hkd_assets', total_assets)
                        
                        if market_type == '美股':
                                self.logger.info(f"💰 美股账户总资产: ${total_assets:,.2f} USD (原始: HK${original_hkd:,.2f}, 汇率: {conversion_rate:.4f})")
                        else:
                                self.logger.info(f"💰 港股账户总资产: HK${total_assets:,.2f}")
                    else:
                        self.logger.warning(f"⚠️ 无法获取账户总资产，使用默认值计算仓位比例")
                        total_assets = 10000.0  # 默认值
                    
                    # 将持仓数据适配为市场列表格式
                    market_data = self._convert_positions_to_market_format(positions, total_assets)
                    
                    if market_data:
                        # 插入数据库作为基准
                        self.market_db.update_baseline_data(market_data, force_update=True)
                        self.logger.info(f"🎯 持仓基准数据已建立: {len(market_data)} 条记录")
                        
                        # 显示基准详情
                        for data in market_data:
                            self.logger.info(f"   📈 {data['代码']}: {data['仓位比例']} ({data['名称']})")
                    else:
                        self.logger.warning("⚠️ 持仓数据转换失败")
                else:
                    self.logger.info("📭 当前账户无持仓，数据库基准保持为空")
                    self.logger.info("🎯 空持仓状态：后续OCR识别到的股票将全部触发买入交易")
            else:
                self.logger.error(f"❌ 获取持仓失败: {position_result.get('error', '未知错误')}")
                
        except Exception as e:
            self.logger.error(f"❌ 初始化持仓基准失败: {e}")
    
    def _convert_positions_to_market_format(self, positions: list, total_assets: float) -> list:
        """将持仓数据转换为市场列表格式
        
        Args:
            positions: 持仓数据列表
            total_assets: 账户总资产
            
        Returns:
            市场列表格式的数据
        """
        try:
            market_data = []
            
            for idx, position in enumerate(positions, 1):
                stock_code = position.get('stock_code', '')
                stock_name = position.get('stock_name', '')
                market_val = position.get('market_val', 0.0)
                cost_price = position.get('cost_price', 0.0)
                nominal_price = position.get('nominal_price', 0.0)
                unrealized_pl_ratio = position.get('unrealized_pl_ratio', 0.0)
                
                if not stock_code:
                    continue
                
                # 计算仓位比例（市值 / 总资产 * 100）
                position_ratio = (market_val / total_assets * 100) if total_assets > 0 else 0.0
                
                # 格式化数据
                market_item = {
                    '序号': str(idx),
                    '代码': stock_code,
                    '名称': stock_name,
                    '仓位比例': f"{position_ratio:.2f}%",
                    '成本价': f"{cost_price:.3f}" if cost_price > 0 else "0.000",
                    '最新价': f"{nominal_price:.3f}" if nominal_price > 0 else "0.000",
                    '盈亏比例': f"{unrealized_pl_ratio:+.2f}%" if unrealized_pl_ratio != 0 else "+0.00%",
                    '状态': '(持仓)'  # 🔥 持仓状态显示为(持仓)
                }
                
                market_data.append(market_item)
                
                # 🔥 显示详细的转换信息（包括汇率转换）
                conversion_rate = position.get('conversion_rate', 1.0)
                original_hkd_val = position.get('original_hkd_market_val', market_val)
                market_type = position.get('market_type', '')
                
                if market_type == '美股' and conversion_rate != 1.0:
                    self.logger.info(f"🔄 转换美股持仓: {stock_code} - 原始HK${original_hkd_val:,.2f} → ${market_val:,.2f} USD → 仓位{position_ratio:.2f}% (汇率: {conversion_rate:.4f})")
                else:
                    self.logger.info(f"🔄 转换港股持仓: {stock_code} - 市值HK${market_val:,.2f} → 仓位{position_ratio:.2f}%")
            
            return market_data
            
        except Exception as e:
            self.logger.error(f"❌ 持仓数据转换失败: {e}")
            return []
    
    
    def setup_ui(self):
        """初始化UI"""
        layout = QVBoxLayout(self)
        layout.setContentsMargins(10, 10, 10, 10)
        layout.setSpacing(10)
        
        # 创建垂直分割器
        splitter = QSplitter(Qt.Vertical)
        
        # 上部分：配置区域（更紧凑）
        config_widget = self.create_config_widget()
        splitter.addWidget(config_widget)
        
        # 下部分：当前市场列表（显示OCR识别结果）
        market_widget = self.create_market_widget()
        splitter.addWidget(market_widget)
        
        # 重新设置分割比例 - 给市场表格更多空间
        splitter.setStretchFactor(0, 2)  # 配置区域占2/5
        splitter.setStretchFactor(1, 3)  # 市场区域占3/5
        
        layout.addWidget(splitter)
        
        self.logger.info("配置面板UI初始化完成")
    
    def create_config_widget(self):
        """创建配置组件"""
        widget = QWidget()
        layout = QVBoxLayout(widget)
        layout.setSpacing(10)  # 紧凑间距
        
        # 识别区域配置
        area_group = self.create_area_config_group()
        layout.addWidget(area_group)
        
        # 交易和监控配置（合并）
        config_group = self.create_main_config_group()
        layout.addWidget(config_group)
        
        # 控制按钮
        control_group = self.create_control_group()
        layout.addWidget(control_group)
        
        # 添加弹性空间，让操作历史获得更多高度
        layout.addStretch(1)
        
        return widget
    
    def create_area_config_group(self):
        """创建区域识别配置组"""
        group = QGroupBox("识别区域配置")
        layout = QVBoxLayout(group)
        
        # 区域选择行
        area_layout = QHBoxLayout()
        
        # 区域状态显示
        self.area_status_label = QLabel("未设置识别区域")
        self.area_status_label.setStyleSheet("color: #666666;")
        area_layout.addWidget(self.area_status_label)
        
        # 框选按钮
        self.select_area_btn = QPushButton("框选识别区域")
        self.select_area_btn.clicked.connect(self.select_area)
        area_layout.addWidget(self.select_area_btn)
        
        # 预览按钮
        self.preview_btn = QPushButton("预览区域")
        self.preview_btn.clicked.connect(self.preview_area)
        self.preview_btn.setEnabled(False)  # 默认禁用，选择区域后启用
        area_layout.addWidget(self.preview_btn)
        
        area_layout.addStretch()
        layout.addLayout(area_layout)
        
        return group
    
    def create_main_config_group(self):
        """创建主配置组（合并交易和监控配置）"""
        group = QGroupBox("监控配置")
        layout = QVBoxLayout(group)
        layout.setSpacing(8)  # 紧凑间距
        
        # 第一行：券商选择和刷新（最顶部）
        row1_layout = QHBoxLayout()
        
        # 券商选择下拉框
        row1_layout.addWidget(QLabel("券商:"))
        from PyQt5.QtWidgets import QComboBox
        self.broker_combo = QComboBox()
        self.broker_combo.setMinimumWidth(150)
        self.broker_combo.setMaximumWidth(200)
        row1_layout.addWidget(self.broker_combo)
        
        # 刷新券商按钮
        self.refresh_brokers_btn = QPushButton("🔄")
        self.refresh_brokers_btn.setMaximumWidth(30)
        self.refresh_brokers_btn.setToolTip("刷新券商列表")
        self.refresh_brokers_btn.clicked.connect(self.refresh_brokers)
        row1_layout.addWidget(self.refresh_brokers_btn)
        
        row1_layout.addWidget(QLabel("  "))  # 分隔符
        
        row1_layout.addWidget(QLabel("可用账户:"))
        self.account_combo = QComboBox()
        self.account_combo.setMinimumWidth(280)
        self.account_combo.setMaximumWidth(350)
        row1_layout.addWidget(self.account_combo)
        
        # 刷新账户按钮
        self.refresh_accounts_btn = QPushButton("🔄")
        self.refresh_accounts_btn.setMaximumWidth(30)
        self.refresh_accounts_btn.setToolTip("刷新账户列表")
        self.refresh_accounts_btn.clicked.connect(self.refresh_accounts)
        row1_layout.addWidget(self.refresh_accounts_btn)
        
        row1_layout.addStretch()
        layout.addLayout(row1_layout)
        
        # 第二行：账户信息显示
        row2_layout = QHBoxLayout()
        
        # 账户资金
        row2_layout.addWidget(QLabel("账户资金:"))
        self.account_funds_label = QLabel("--")
        self.account_funds_label.setStyleSheet("font-weight: bold; color: #2e7d32;")
        self.account_funds_label.setMinimumWidth(120)
        row2_layout.addWidget(self.account_funds_label)
        
        # 更新时间
        self.funds_update_time_label = QLabel("--")
        self.funds_update_time_label.setStyleSheet("color: #666666; font-size: 10px;")
        self.funds_update_time_label.setMinimumWidth(80)
        row2_layout.addWidget(self.funds_update_time_label)
        
        row2_layout.addStretch()
        layout.addLayout(row2_layout)
        
        # 第三行：交易密码和自动交易
        row3_layout = QHBoxLayout()
        row3_layout.addWidget(QLabel("交易密码:"))
        
        self.password_edit = QLineEdit()
        self.password_edit.setEchoMode(QLineEdit.Password)
        self.password_edit.setPlaceholderText("请输入富途交易密码")
        self.password_edit.setMaximumWidth(150)
        row3_layout.addWidget(self.password_edit)
        
        # 显示/隐藏密码按钮
        self.show_pwd_btn = QPushButton("👁")
        self.show_pwd_btn.setMaximumWidth(25)
        self.show_pwd_btn.pressed.connect(lambda: self.password_edit.setEchoMode(QLineEdit.Normal))
        self.show_pwd_btn.released.connect(lambda: self.password_edit.setEchoMode(QLineEdit.Password))
        row3_layout.addWidget(self.show_pwd_btn)
        
        row3_layout.addWidget(QLabel("  "))  # 分隔符
        
        self.auto_trade_cb = QCheckBox("启用自动交易")
        row3_layout.addWidget(self.auto_trade_cb)
        
        row3_layout.addStretch()
        layout.addLayout(row3_layout)
        
        # 第四行：运行时间（改为分钟倒计时）
        row4_layout = QHBoxLayout()
        row4_layout.addWidget(QLabel("运行时长:"))
        
        self.runtime_spin = QSpinBox()
        self.runtime_spin.setRange(0, 9999)
        self.runtime_spin.setValue(0)
        self.runtime_spin.setSuffix(" 分钟")
        self.runtime_spin.setSpecialValueText("持续运行")
        self.runtime_spin.setMaximumWidth(100)
        row4_layout.addWidget(self.runtime_spin)
        
        row4_layout.addWidget(QLabel("(0=持续运行)"))
        
        row4_layout.addStretch()
        layout.addLayout(row4_layout)
        
        # 第五行：买单价格偏移配置
        row5_layout = QHBoxLayout()
        row5_layout.addWidget(QLabel("挂买单价格高于成本价:"))
        
        from PyQt5.QtWidgets import QDoubleSpinBox
        self.buy_price_offset_spin = QDoubleSpinBox()
        self.buy_price_offset_spin.setRange(0.0, 999.0)
        self.buy_price_offset_spin.setValue(0.5)
        self.buy_price_offset_spin.setSingleStep(0.1)
        self.buy_price_offset_spin.setDecimals(2)
        self.buy_price_offset_spin.setMaximumWidth(80)
        row5_layout.addWidget(self.buy_price_offset_spin)
        
        row5_layout.addWidget(QLabel("(如填0.5，成本价30，则买单价格30.5)"))
        
        row5_layout.addStretch()
        layout.addLayout(row5_layout)
        
        # 第六行：卖单价格偏移配置
        row6_layout = QHBoxLayout()
        row6_layout.addWidget(QLabel("挂卖单价格低于成本价:"))
        
        self.sell_price_offset_spin = QDoubleSpinBox()
        self.sell_price_offset_spin.setRange(0.0, 999.0)
        self.sell_price_offset_spin.setValue(0.5)
        self.sell_price_offset_spin.setSingleStep(0.1)
        self.sell_price_offset_spin.setDecimals(2)
        self.sell_price_offset_spin.setMaximumWidth(80)
        row6_layout.addWidget(self.sell_price_offset_spin)
        
        row6_layout.addWidget(QLabel("(如填0.5，市价30，则卖单价格29.5)"))
        
        row6_layout.addStretch()
        layout.addLayout(row6_layout)
        
        return group
    

    
    def create_control_group(self):
        """创建控制按钮组"""
        group = QGroupBox("控制操作")
        layout = QHBoxLayout(group)
        
        # 开始监控按钮
        self.start_btn = QPushButton("开始监控")
        self.start_btn.setStyleSheet("""
            QPushButton {
                background-color: #4CAF50;
                color: white;
                font-weight: bold;
                padding: 10px 20px;
                border: none;
                border-radius: 5px;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QPushButton:disabled {
                background-color: #cccccc;
            }
        """)
        self.start_btn.clicked.connect(self.start_monitoring_clicked)
        layout.addWidget(self.start_btn)
        
        # 停止监控按钮
        self.stop_btn = QPushButton("停止监控")
        self.stop_btn.setStyleSheet("""
            QPushButton {
                background-color: #f44336;
                color: white;
                font-weight: bold;
                padding: 10px 20px;
                border: none;
                border-radius: 5px;
            }
            QPushButton:hover {
                background-color: #da190b;
            }
            QPushButton:disabled {
                background-color: #cccccc;
            }
        """)
        self.stop_btn.clicked.connect(self.stop_monitoring_clicked)
        self.stop_btn.setEnabled(False)
        layout.addWidget(self.stop_btn)
        
        # 测试OCR按钮
        self.test_ocr_btn = QPushButton("测试OCR")
        self.test_ocr_btn.clicked.connect(self.test_ocr)
        layout.addWidget(self.test_ocr_btn)
        
        
        # 窗口置顶勾选框
        self.always_on_top_cb = QCheckBox("窗口置顶")
        self.always_on_top_cb.setToolTip("勾选后窗口将保持在最前端显示")
        self.always_on_top_cb.stateChanged.connect(self.on_always_on_top_changed)
        layout.addWidget(self.always_on_top_cb)
        
        layout.addStretch()
        
        return group
    
    def create_market_widget(self):
        """创建当前市场组件（显示OCR识别结果）"""
        widget = QWidget()
        layout = QVBoxLayout(widget)
        
        # 标题和操作按钮
        header_layout = QHBoxLayout()
        header_layout.addWidget(QLabel("当前市场"))
        
        # 交易历史按钮
        self.trading_history_btn = QPushButton("交易历史")
        self.trading_history_btn.setMaximumWidth(80)
        self.trading_history_btn.clicked.connect(self.show_trading_history)
        header_layout.addWidget(self.trading_history_btn)
        
        # 刷新按钮
        refresh_btn = QPushButton("刷新")
        refresh_btn.setMaximumWidth(60)
        refresh_btn.clicked.connect(self.refresh_market_data)
        header_layout.addWidget(refresh_btn)
        
        # 清空按钮
        clear_btn = QPushButton("清空")
        clear_btn.setMaximumWidth(60)
        clear_btn.clicked.connect(self.clear_market_data)
        header_layout.addWidget(clear_btn)
        
        header_layout.addStretch()
        layout.addLayout(header_layout)
        
        # 市场数据表格（显示OCR识别结果）
        from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QHeaderView
        self.market_table = QTableWidget()
        self.market_table.setColumnCount(7)  # 移除序号列
        self.market_table.setHorizontalHeaderLabels([
            "代码", "名称", "仓位比例", "成本价", "最新价", "盈亏比例", "状态"
        ])
        
        # 设置表格样式 - 所有列等宽
        header = self.market_table.horizontalHeader()
        for i in range(7):  # 7列而不是8列
            header.setSectionResizeMode(i, QHeaderView.Stretch)  # 所有列等宽
        
        self.market_table.setAlternatingRowColors(True)
        self.market_table.setSelectionBehavior(QTableWidget.SelectRows)
        self.market_table.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        
        # 设置表格高度以显示更多数据
        layout.addWidget(self.market_table)
        
        return widget
    
    def connect_signals(self):
        """连接信号"""
        # 配置变更信号连接 - 失焦保存
        self.password_edit.editingFinished.connect(self.on_config_changed)
        self.auto_trade_cb.stateChanged.connect(self.on_config_changed)
        self.runtime_spin.editingFinished.connect(self.on_config_changed)
        self.buy_price_offset_spin.editingFinished.connect(self.on_config_changed)
        self.sell_price_offset_spin.editingFinished.connect(self.on_config_changed)
        self.broker_combo.currentIndexChanged.connect(self.on_broker_changed)
        self.account_combo.currentIndexChanged.connect(self.on_account_changed)
    
    def load_config(self):
        """加载配置"""
        try:
            # 加载识别区域
            current_area = self.config_manager.get('area.current_area')
            if current_area:
                self.area_status_label.setText(f"已设置区域: {current_area}")
                self.area_status_label.setStyleSheet("color: #006600;")
                self.preview_btn.setEnabled(True)
            else:
                self.area_status_label.setText("未设置识别区域")
                self.area_status_label.setStyleSheet("color: #666666;")
                self.preview_btn.setEnabled(False)
            
            # 交易密码不保存到配置文件，每次启动时为空
            self.password_edit.setText('')
            
            auto_trade = self.config_manager.get('trading.auto_trade', False)
            self.auto_trade_cb.setChecked(auto_trade)
            
            # 加载运行时长配置
            runtime = self.config_manager.get('monitor.runtime_minutes', 0)
            self.runtime_spin.setValue(runtime)
            
            # 加载买单价格偏移配置
            buy_price_offset = self.config_manager.get('trading.buy_price_offset', 0.5)
            self.buy_price_offset_spin.setValue(buy_price_offset)
            
            # 加载卖单价格偏移配置
            sell_price_offset = self.config_manager.get('trading.sell_price_offset', 0.5)
            self.sell_price_offset_spin.setValue(sell_price_offset)
            
            # 🔥 修复：先获取保存的券商和账户信息
            selected_broker = self.config_manager.get('trading.selected_broker', '')
            selected_acc_id = self.config_manager.get('trading.selected_acc_id', '')
            
            # 加载账户列表（配置加载阶段，不自动选择第一个券商）
            self.refresh_brokers(auto_select_first=False)
            
            # 🔥 保存选择状态，稍后在信号连接后恢复
            self._pending_broker_selection = selected_broker
            self._pending_account_selection = selected_acc_id
            
            self.logger.info(f"💾 保存待恢复状态: 券商={selected_broker}, 账户={selected_acc_id}")
            
            # 初始化市场数据
            self.load_market_data()
            
            self.logger.info("配置加载完成")
            
        except Exception as e:
            self.logger.error(f"加载配置失败: {e}")
    
    def load_market_data(self):
        """加载市场数据（OCR识别结果）"""
        try:
            # 初始化空的市场数据表格
            self.market_table.setRowCount(0)
            # 初始化市场数据存储
            if not hasattr(self, 'market_data_list'):
                self.market_data_list = []
            self.logger.info("市场数据表格已初始化，等待OCR识别结果")
            
        except Exception as e:
            self.logger.error(f"初始化市场数据失败: {e}")
    
    def update_market_data(self, ocr_result):
        """更新市场数据（根据OCR识别结果）- 基于名称更新"""
        try:
            from PyQt5.QtWidgets import QTableWidgetItem
            
            if not ocr_result:
                return
            
            # 解析OCR结果并提取市场数据
            new_market_data = self.parse_market_data_from_ocr(ocr_result)
            
            # 如果没有解析到新数据，跳过更新
            if not new_market_data:
                self.logger.warning("⚠️ 没有解析到新的市场数据，跳过更新")
                return
                
            self.logger.info(f"🔍 OCR解析结果: {len(new_market_data)} 条新数据")
            
            # 初始化市场数据存储
            if not hasattr(self, 'market_data_list'):
                self.market_data_list = []
            
            # 🔥 重要修复：不再从配置文件加载历史数据，完全以数据库为准
            if not hasattr(self, 'previous_market_data'):
                # 初始化为空，所有历史数据都从数据库获取
                self.previous_market_data = []
                self.logger.info(f"🔄 初始化历史数据为空，以数据库为唯一数据源")
            
            # 重要：在处理新数据之前先备份当前数据，这样才能检测到变化
            # 移除这行，将在最后更新：self.previous_market_data = [data.copy() for data in self.market_data_list]
            
            # 基于代码更新数据：相同代码替换，不同代码追加
            for new_data in new_market_data:
                code = new_data.get('代码', '')
                if not code:  # 跳过没有代码的数据
                    continue
                
                # 查找是否存在相同代码的数据
                found_index = -1
                for i, existing_data in enumerate(self.market_data_list):
                    if existing_data.get('代码', '') == code:
                        found_index = i
                        break
                
                if found_index >= 0:
                    # 替换现有数据
                    self.market_data_list[found_index] = new_data
                    self.logger.info(f"📝 更新股票数据: {code}")
                else:
                    # 追加新数据
                    self.market_data_list.append(new_data)
                    self.logger.info(f"➕ 添加新股票: {code}")
            
            # 重新分配系统内部序号
            for i, data in enumerate(self.market_data_list):
                data['序号'] = str(i + 1)
            
            
            # 更新表格显示
            self.refresh_market_table()
            
            # 检查是否包含"全部成交"字符串 - 这是触发实际交易的必要条件
            has_partial_transaction = self.check_partial_transaction_in_ocr(ocr_result)
            
            # 但是无论是否有"全部成交"，都要进行仓位比对和记录
            # 传递"全部成交"状态信息给比对方法
            self.trigger_monitoring_comparison(has_partial_transaction, ocr_result)
            
            self.logger.info(f"市场数据已更新，当前共 {len(self.market_data_list)} 条记录")
            
        except Exception as e:
            self.logger.error(f"更新市场数据失败: {e}")
    
    def check_partial_transaction_in_ocr(self, ocr_result):
        """检查OCR结果中是否包含"全部成交"字符串"""
        try:
            if not ocr_result:
                return False
            
            # 获取所有OCR识别的文本
            all_texts = []
            
            # 检查原始OCR结果
            if isinstance(ocr_result, dict):
                # 从text_items中提取文本
                text_items = ocr_result.get('text_items', [])
                if text_items:
                    for item in text_items:
                        if isinstance(item, dict):
                            text = item.get('text', '')
                            if text:
                                all_texts.append(text)
                        elif isinstance(item, str):
                            all_texts.append(item)
                
                # 从enhanced_data中提取文本
                enhanced_data = ocr_result.get('enhanced_data', {})
                if enhanced_data and isinstance(enhanced_data, dict):
                    potential_table_data = enhanced_data.get('potential_table_data', [])
                    if potential_table_data:
                        for row in potential_table_data:
                            if isinstance(row, list):
                                for cell in row:
                                    if isinstance(cell, dict):
                                        text = cell.get('text', '')
                                        if text:
                                            all_texts.append(text)
                
                # 从直接字典项中提取文本 (检查text和rec_txt字段)
                for key, value in ocr_result.items():
                    if isinstance(value, dict):
                        # 检查text字段
                        if 'text' in value:
                            text = value.get('text', '')
                            if text:
                                all_texts.append(text)
                        # 检查rec_txt字段 (OCR原始结果格式)
                        if 'rec_txt' in value:
                            text = value.get('rec_txt', '')
                            if text:
                                all_texts.append(text)
            
            # 合并所有文本进行检查
            combined_text = ' '.join(all_texts)
            
            # 检查是否包含"全部成交"
            has_partial_transaction = "全部成交" in combined_text
            
            if has_partial_transaction:
                self.logger.info(f"🎯 在OCR结果中发现\"全部成交\"字符串")
                self.logger.info(f"🔍 提取到的文本总数: {len(all_texts)} 条")
            else:
                self.logger.debug(f"⚪ OCR结果中未发现\"全部成交\"字符串")
                self.logger.debug(f"🔍 提取到的文本总数: {len(all_texts)} 条")
            
            return has_partial_transaction
            
        except Exception as e:
            self.logger.error(f"检查\"全部成交\"字符串失败: {e}")
            return False
    
    def refresh_market_table(self):
        """刷新市场数据表格显示"""
        try:
            from PyQt5.QtWidgets import QTableWidgetItem
            
            if not hasattr(self, 'market_data_list'):
                self.market_data_list = []
            
            # 设置表格行数
            self.market_table.setRowCount(len(self.market_data_list))
            
            for row, data in enumerate(self.market_data_list):
                # 填充表格数据（移除序号列）
                self.market_table.setItem(row, 0, QTableWidgetItem(data.get('代码', '')))
                self.market_table.setItem(row, 1, QTableWidgetItem(data.get('名称', '')))
                self.market_table.setItem(row, 2, QTableWidgetItem(data.get('仓位比例', '')))
                self.market_table.setItem(row, 3, QTableWidgetItem(data.get('成本价', '')))
                self.market_table.setItem(row, 4, QTableWidgetItem(data.get('最新价', '')))
                self.market_table.setItem(row, 5, QTableWidgetItem(data.get('盈亏比例', '')))
                self.market_table.setItem(row, 6, QTableWidgetItem(data.get('状态', '')))
                
                # 根据盈亏比例设置颜色（中国股市习惯：红涨绿跌）
                profit_loss = data.get('盈亏比例', '')
                if '+' in profit_loss:
                    # 盈利，红色
                    for col in range(7):  # 7列而不是8列
                        item = self.market_table.item(row, col)
                        if item:
                            item.setForeground(Qt.red)
                elif '-' in profit_loss:
                    # 亏损，绿色
                    for col in range(7):  # 7列而不是8列
                        item = self.market_table.item(row, col)
                        if item:
                            item.setForeground(Qt.darkGreen)
                elif profit_loss.startswith('0') or '0.00%' in profit_loss:
                    # 持平，黑色
                    for col in range(7):  # 7列而不是8列
                        item = self.market_table.item(row, col)
                        if item:
                            item.setForeground(Qt.black)
            
        except Exception as e:
            self.logger.error(f"刷新市场表格失败: {e}")
    
    def trigger_monitoring_comparison(self, has_partial_transaction=False, ocr_result=None):
        """触发监控比对逻辑 - 比对当前和数据库基准数据，记录所有变化并在满足条件时触发交易操作"""
        try:
            # 🔥 调试日志：函数入口
            self.logger.info(f"🎯 trigger_monitoring_comparison 被调用: has_partial_transaction={has_partial_transaction}")
            
            # 🔥 优化：第一次监控时加载持仓缓存
            if not self.initial_positions_loaded:
                self.logger.info("🔍 第一次监控比对，加载初始持仓缓存...")
                # 从当前市场数据获取需要缓存的股票代码
                codes_to_cache = []
                if hasattr(self, 'market_data_list') and self.market_data_list:
                    codes_to_cache = [item.get('代码', '') for item in self.market_data_list if item.get('代码')]
                self._load_initial_positions_cache(codes_to_cache)
            
            # 检查数据库可用性
            if not self.market_db:
                self.logger.error("❌ 数据库不可用，跳过比对")
                return
            else:
                self.logger.info(f"✅ 数据库连接正常: {type(self.market_db)}")
                
            # 检查当前市场数据
            if not hasattr(self, 'market_data_list') or not self.market_data_list:
                self.logger.info("📋 当前市场数据为空，跳过比对")
                return
            else:
                self.logger.info(f"✅ 当前市场数据: {len(self.market_data_list)} 条")
            
            # 🔥 关键步骤1：从数据库获取上一次的基准数据（用于比较）
            self.logger.info("🔍 【步骤1】获取上一次的基准数据用于比较...")
            baseline_data = self.market_db.get_baseline_data()
            
            # 🔥 修复：空基准时应该触发新股票买入交易，而不是直接建立基准
            if not baseline_data:
                self.logger.info("🎯 【空持仓状态】数据库基准为空，所有OCR识别股票将触发买入交易...")
                
                # 设置空的基准数据用于比对
                self.previous_market_data = []
                self.logger.info("✅ 基准数据已设置为空，将与当前OCR数据进行比较")
                
                # 🔥 继续执行比对逻辑，让所有股票都被识别为新增股票
            else:
                # 🔍 关键步骤2：设置内存中的基准数据用于本次比对
                self.logger.info("🔍 【步骤2】设置基准数据用于本次比对...")
                self.previous_market_data = baseline_data
                self.logger.info(f"✅ 基准数据已设置，将与当前OCR数据进行比较")
                
            # 检查当前数据是否为空
            if not self.market_data_list:
                self.logger.info("当前市场列表为空，跳过比对")
                return
            
            # 获取账户资金
            account_funds = self.get_current_account_funds()
            
            if has_partial_transaction:
                self.logger.info("🔍 开始监控数据比对（检测到\"全部成交\"，将触发交易）...")
                # 清空本轮交易信号收集列表
                self.current_trading_signals = []
            else:
                self.logger.info("📝 开始仓位变化记录（未检测到\"全部成交\"，仅记录不交易）...")
            
            # 创建代码到数据的映射，便于查找
            current_data_map = {data.get('代码', ''): data for data in self.market_data_list if data.get('代码', '')}
            previous_data_map = {data.get('代码', ''): data for data in self.previous_market_data if data.get('代码', '')}
            
            # 获取所有代码（当前的和之前的）
            all_codes = set(current_data_map.keys()) | set(previous_data_map.keys())
            
            self.logger.info(f"🔍 当前数据股票: {list(current_data_map.keys())}")
            self.logger.info(f"🔍 历史数据股票: {list(previous_data_map.keys())}")
            self.logger.info(f"🔍 开始比对 {len(all_codes)} 只股票")
            
            # 🔥 调试：打印基准数据详情
            self.logger.info(f"📊 交易基准数据详情:")
            for code, data in previous_data_map.items():
                position = data.get('仓位比例', 'N/A')
                self.logger.info(f"   {code}: {position}")
            
            self.logger.info(f"📊 当前OCR数据详情:")
            for code, data in current_data_map.items():
                position = data.get('仓位比例', 'N/A')
                self.logger.info(f"   {code}: {position}")
            
            for code in all_codes:
                current_data = current_data_map.get(code)
                previous_data = previous_data_map.get(code)
                
                # 获取OCR状态字段（通常是每行数据的最后一个字段）
                ocr_status = self.extract_status_from_data(current_data, ocr_result)
                
                # 🔥 修复核心逻辑：优先检查真实持仓，避免误判
                if has_partial_transaction and current_data and not previous_data:
                    # 数据库基准为空，但需要检查是否真的是新增持仓
                    try:
                        # 获取真实持仓信息
                        real_position_info = self._get_own_stock_info(code)
                        real_position_ratio = real_position_info.get('position_ratio', 0.0)
                        
                        if real_position_ratio > 0.1:  # 如果真实持仓大于0.1%，说明不是新增持仓
                            self.logger.info(f"🔍 {code} 数据库基准为空，但真实持仓={real_position_ratio:.2f}%，按仓位比对处理")
                            # 构造虚拟的previous_data，基于真实持仓
                            virtual_previous_data = {
                                '代码': code,
                                '仓位比例': f"{real_position_ratio:.2f}%"
                            }
                            self.compare_position_change(code, current_data, virtual_previous_data, 
                                                       has_partial_transaction, ocr_status, account_funds)
                        else:
                            # 真实持仓为0，确实是新增持仓
                            self.logger.info(f"🔍 {code} 确认为新增持仓，真实持仓={real_position_ratio:.2f}%")
                            self.trigger_new_purchase(code, current_data, 
                                                    has_partial_transaction, ocr_status, account_funds)
                    except Exception as e:
                        self.logger.error(f"❌ 检查 {code} 真实持仓失败: {e}，按新增持仓处理")
                        self.trigger_new_purchase(code, current_data, 
                                                has_partial_transaction, ocr_status, account_funds)
                elif current_data and previous_data:
                    # 两边都存在，比对仓位比例
                    self.compare_position_change(code, current_data, previous_data, 
                                               has_partial_transaction, ocr_status, account_funds)
                elif current_data and not previous_data and not has_partial_transaction:
                    # 非交易状态下的新增持仓（正常情况）
                    self.trigger_new_purchase(code, current_data, 
                                            has_partial_transaction, ocr_status, account_funds)
                elif not current_data and previous_data:
                    # 清仓
                    self.trigger_full_sale(code, previous_data, 
                                         has_partial_transaction, ocr_status, account_funds)
            
            # 如果检测到"全部成交"，处理收集到的交易信号
            if has_partial_transaction and hasattr(self, 'current_trading_signals'):
                self.process_collected_trading_signals()
            
            # 如果检测到"全部成交"，更新之前的待成交记录
            if has_partial_transaction:
                for code in all_codes:
                    if code in current_data_map:
                        current_data = current_data_map[code]
                        ocr_status = self.extract_status_from_data(current_data, ocr_result)
                        self.config_manager.update_pending_trading_records(code, ocr_status)
            
            # 🔥 保存OCR历史记录到数据库
            self.market_db.save_ocr_history(self.market_data_list, has_partial_transaction)
            
            # 🔥 关键步骤3：比较完成后，更新数据库基准数据为本次OCR数据（供下次比较使用）
            self.logger.info("🔍 【步骤3】比较完成，更新数据库基准数据为本次OCR数据...")
            self.logger.info(f"🔍 准备更新 {len(self.market_data_list)} 条数据到数据库基准:")
            for data in self.market_data_list:
                stock_code = data.get('代码', '')
                position_ratio = data.get('仓位比例', '')
                if stock_code:
                    self.logger.info(f"   将更新: {stock_code} → {position_ratio}")
            
            # 执行更新操作
            self.market_db.update_baseline_data(self.market_data_list, force_update=True)
            self.logger.info(f"✅ 数据库基准数据已更新为本次OCR数据，供下次比较使用")
            
            # 记录交易信号处理情况
            if has_partial_transaction and hasattr(self, 'current_trading_signals') and self.current_trading_signals:
                self.logger.info(f"🎯 检测到交易信号，已处理完毕")
            else:
                self.logger.info(f"📊 本轮比对无交易信号")
                    
        except Exception as e:
            self.logger.error(f"监控比对失败: {e}")
    
    def _is_signal_debounced(self, stock_code, action, position_diff):
        """检查交易信号是否在防抖期内"""
        try:
            import time
            import hashlib
            
            current_time = time.time()
            
            # 生成信号哈希（股票代码+动作+仓位差异）
            signal_str = f"{stock_code}_{action}_{position_diff:.2f}"
            signal_hash = hashlib.md5(signal_str.encode()).hexdigest()
            
            # 检查是否存在相同的信号记录
            if stock_code in self.trading_debounce:
                last_signal = self.trading_debounce[stock_code]
                time_diff = current_time - last_signal['timestamp']
                
                # 如果是相同信号且在防抖时间内
                if (last_signal['signal_hash'] == signal_hash and 
                    time_diff < self.debounce_time):
                    self.logger.info(f"🛡️ {stock_code} 防抖保护: {action} {position_diff:.2f}% (距离上次 {time_diff:.1f}s < {self.debounce_time}s)")
                    return True
            
            # 记录新的信号
            self.trading_debounce[stock_code] = {
                'timestamp': current_time,
                'signal_hash': signal_hash
            }
            
            return False
            
        except Exception as e:
            self.logger.error(f"防抖检查失败: {e}")
            return False
    
    def save_ocr_history_record(self, market_data, has_transaction_signal):
        """保存OCR历史记录到数据库"""
        try:
            from datetime import datetime
            
            # 创建OCR历史记录
            ocr_record = {
                'timestamp': datetime.now().isoformat(),
                'market_data': market_data.copy(),
                'has_transaction_signal': has_transaction_signal,
                'record_count': len(market_data)
            }
            
            # 获取现有OCR历史记录
            ocr_history = self.config_manager.get('market.ocr_history', [])
            
            # 添加新记录
            ocr_history.append(ocr_record)
            
            # 限制历史记录数量（保留最近100条）
            if len(ocr_history) > 100:
                ocr_history = ocr_history[-100:]
            
            # 保存OCR历史记录
            self.config_manager.set('market.ocr_history', ocr_history)
            
            self.logger.info(f"💾 OCR历史记录已保存: {len(market_data)}条数据, 交易信号: {has_transaction_signal}")
            
        except Exception as e:
            self.logger.error(f"保存OCR历史记录失败: {e}")
    
    def update_trading_baseline_data(self, stock_code, new_position):
        """更新指定股票的交易基准数据（仅在用户确认交易后调用）"""
        try:
            if not self.market_db:
                self.logger.error("❌ 数据库不可用，无法更新基准")
                return
            
            # 🔥 使用数据库更新基准数据
            self.market_db.update_single_baseline(stock_code, new_position)
            
            # 更新内存中的基准数据（重新从数据库获取）
            self.previous_market_data = self.market_db.get_baseline_data()
            
        except Exception as e:
            self.logger.error(f"更新 {stock_code} 交易基准失败: {e}")
    
    def remove_latest_pending_trade_record(self, action, stock_code):
        """删除最新的pending状态交易记录（用户取消交易时调用）"""
        try:
            trading_records = self.config_manager.get_config().get('trading', {}).get('records', [])
            
            # 从最新记录开始查找匹配的pending记录
            for i in range(len(trading_records) - 1, -1, -1):
                record = trading_records[i]
                if (record.get('action', '').startswith(f'交易信号-{action}') and 
                    stock_code in record.get('details', '') and
                    record.get('status') == 'pending'):
                    
                    # 删除这条记录
                    removed_record = trading_records.pop(i)
                    self.config_manager.update_config('trading.records', trading_records)
                    
                    self.logger.info(f"🗑️ 已删除取消的交易记录: {action} {stock_code}")
                    return True
            
            self.logger.warning(f"⚠️ 未找到匹配的pending交易记录: {action} {stock_code}")
            return False
            
        except Exception as e:
            self.logger.error(f"删除pending交易记录失败: {e}")
            return False
    
    def clear_database_history(self):
        """清空数据库历史数据"""
        try:
            if not self.market_db:
                self.logger.error("❌ 数据库不可用")
                return
            
            # 清空基准数据和OCR历史
            self.market_db.clear_baseline_data()
            self.market_db.clear_ocr_history()
            
            # 清空内存中的数据
            self.previous_market_data = []
            
            self.logger.info("🧹 数据库历史数据已清空")
            
        except Exception as e:
            self.logger.error(f"清空数据库历史失败: {e}")
    
    def extract_status_from_data(self, data, ocr_result):
        """从数据中提取状态字段（通常是最后一个字段）"""
        try:
            if not data:
                return "未知状态"
            
            # 尝试获取数据中的状态字段
            # 通常状态是最后一个字段，比如"未成交"、"全部成交"等
            status_fields = ['状态', '交易状态', '成交状态']
            for field in status_fields:
                if field in data:
                    return data[field]
            
            # 如果没有明确的状态字段，尝试从数据的所有值中找到状态相关的字符串
            for key, value in data.items():
                if isinstance(value, str) and any(keyword in value for keyword in ['成交', '交易', '挂单', '撤单']):
                    return value
            
            # 如果数据中没有状态信息，尝试从原始OCR结果中推断
            # 这里可以根据需要扩展逻辑
            stock_code = data.get('代码', '')
            if stock_code and ocr_result:
                # 这里可以添加更复杂的OCR状态提取逻辑
                pass
            
            return "未知状态"
            
        except Exception as e:
            self.logger.error(f"提取状态字段失败: {e}")
            return "未知状态"
    
    def compare_position_change(self, code, current_data, previous_data, 
                               has_partial_transaction=False, ocr_status="未知状态", account_funds=0):
        """比对仓位变化"""
        try:
            # 获取监控组合的当前仓位
            monitor_position_str = current_data.get('仓位比例', '').replace('%', '').strip()
            
            # 解析监控仓位比例数字
            try:
                monitor_position = float(monitor_position_str) if monitor_position_str else 0
            except ValueError:
                self.logger.warning(f"⚠️ 无法解析监控仓位比例 - {code}: {monitor_position_str}")
                return
                
            # 🔥 修复核心逻辑：获取真实持仓进行正确的交易方向判断
            # 获取真实持仓信息（仅在有"全部成交"时才调用）
            if has_partial_transaction:
                try:
                    own_info = self._get_own_stock_info(code)
                    own_position = own_info['position_ratio']  # 自有组合仓位比例
                    own_market_price = own_info['market_price']
                    own_quantity = own_info['quantity']
                    self.logger.info(f"✅ {code} 获取到真实持仓: {own_position:.2f}%，{own_quantity}股")
                except Exception as e:
                    self.logger.error(f"❌ 获取真实持仓失败: {e}")
                    own_position = 0
                    own_market_price = 100.0
                    own_quantity = 0
            else:
                # 非交易状态时，使用数据库基准数据进行变化检测
                baseline_position_str = previous_data.get('仓位比例', '').replace('%', '').strip() if previous_data else '0'
                try:
                    own_position = float(baseline_position_str) if baseline_position_str else 0
                except ValueError:
                    own_position = 0
                own_market_price = 100.0
                own_quantity = 0
                
            # 🔥 正确计算：当前监控仓位 vs 真实持仓的差异  
            position_diff = monitor_position - own_position
            
            # 🔥 详细仓位对比日志
            self.logger.info(f"📊 【{code} 仓位对比分析】")
            self.logger.info(f"   🏦 {'真实持仓' if has_partial_transaction else '基准仓位'}: {own_position:.2f}%")
            self.logger.info(f"   👁️ 当前监控仓位: {monitor_position:.2f}%")
            self.logger.info(f"   📈 仓位差异: {position_diff:+.2f}% ({'需要买入' if position_diff > 0 else '需要卖出' if position_diff < 0 else '无变化'})")
            
            # 检查仓位差异是否足够触发交易
            if abs(position_diff) < 0.1:  # 微小差异忽略
                self.logger.info(f"📊 {code} 仓位差异微小 ({position_diff:+.2f}%)，忽略此次变化")
                return
            
            # 🔥 正确的交易方向判断
            direction = "买入" if position_diff > 0 else "卖出"
            abs_position_diff = abs(position_diff)
            
            # 🔥 移除重复计算：交易参数将在 execute_trading_action 中统一计算
            
            # 注意：交易记录将在 execute_trading_action 中统一记录，避免重复记录
            
            # 状态判断和日志记录
            if has_partial_transaction:
                self.logger.info(f"🚨 【{code} 交易决策】")
                self.logger.info(f"   📊 仓位差异: {position_diff:+.2f}% ({'富途持仓<监控仓位' if position_diff > 0 else '富途持仓>监控仓位' if position_diff < 0 else '仓位一致'})")
                self.logger.info(f"   ⚡ OCR状态: {ocr_status}")
                self.logger.info(f"   ✅ 条件达标，准备触发{'买入' if position_diff > 0 else '卖出'}交易")
                
                # 🔥 防抖检查 - 防止重复触发相同交易
                if self._is_signal_debounced(code, direction, abs_position_diff):
                    self.logger.warning(f"🛡️ {code} 交易信号被防抖保护阻止，跳过重复操作")
                    return
                
                # 🔥 修复：正确传递仓位参数
                # 条件满足，触发实际交易
                if position_diff > 0:
                    # 监控仓位 > 自有仓位 → 买入
                    self.logger.info(f"🔍 调试：position_diff={position_diff:.2f}% > 0，执行买入操作")
                    self.trigger_buy_operation(code, current_data, abs_position_diff, own_position, monitor_position)
                else:
                    # 监控仓位 < 自有仓位 → 卖出
                    self.logger.info(f"🔍 调试：position_diff={position_diff:.2f}% < 0，执行卖出操作")
                    self.trigger_sell_operation(code, current_data, abs_position_diff, own_position, monitor_position)
            else:
                self.logger.info(f"⏸️ 【{code} 交易决策】")
                self.logger.info(f"   📊 仓位差异: {position_diff:+.2f}%")
                self.logger.info(f"   ⚡ OCR状态: {ocr_status}")
                self.logger.info(f"   ⚠️ 状态未达标（需要检测到'全部成交'），暂不触发交易")
                
        except Exception as e:
            self.logger.error(f"比对仓位变化失败 - {code}: {e}")
    
    def trigger_new_purchase(self, code, current_data, 
                            has_partial_transaction=False, ocr_status="未知状态", account_funds=0):
        """触发新购入操作"""
        try:
            position_str = current_data.get('仓位比例', '').replace('%', '').strip()
            position = float(position_str) if position_str else 0
            
            if position > 0:
                # 🔥 移除重复计算：交易参数将在 execute_trading_action 中统一计算
                
                # 注意：交易记录将在 execute_trading_action 中统一记录，避免重复记录
                
                # 状态判断和日志记录
                if has_partial_transaction:
                    self.logger.info(f"🆕 {code} 新增持仓: 0% → {position:.2f}% | 状态: {ocr_status} | ✅ 条件达标，触发交易")
                    
                    # 🔥 防抖检查 - 防止重复触发相同交易
                    if self._is_signal_debounced(code, "买入", position):
                        self.logger.warning(f"🛡️ {code} 新增持仓交易信号被防抖保护阻止，跳过重复操作")
                        return
                    
                    # 新增持仓作为买入操作
                    # 🔥 修复：传入正确的仓位参数
                    self.execute_trading_action('买入', code, position, 
                                               previous_position=0.0,  # 从0%开始
                                               current_position=position)  # 到当前仓位
                else:
                    self.logger.info(f"🆕 {code} 新增持仓: 0% → {position:.2f}% | 状态: {ocr_status} | ⚠️ 状态未达标，暂不触发交易")
            
        except Exception as e:
            self.logger.error(f"处理新购入失败 - {code}: {e}")
    
    def trigger_full_sale(self, code, previous_data, 
                         has_partial_transaction=False, ocr_status="未知状态", account_funds=0):
        """触发全部卖出操作"""
        try:
            position_str = previous_data.get('仓位比例', '').replace('%', '').strip()
            position = float(position_str) if position_str else 0
            
            if position > 0:
                # 🔥 移除重复计算：交易参数将在 execute_trading_action 中统一计算
                
                # 注意：交易记录将在 execute_trading_action 中统一记录，避免重复记录
                
                # 状态判断和日志记录
                if has_partial_transaction:
                    self.logger.info(f"🔴 {code} 清仓操作: {position:.2f}% → 0% | 状态: {ocr_status} | ✅ 条件达标，触发交易")
                    
                    # 🔥 防抖检查 - 防止重复触发相同交易
                    if self._is_signal_debounced(code, "卖出", position):
                        self.logger.warning(f"🛡️ {code} 清仓交易信号被防抖保护阻止，跳过重复操作")
                        return
                    
                    # 清仓时卖出所有该股票的持仓
                    # 🔥 修复：传入正确的仓位参数
                    self.execute_trading_action('卖出', code, position, is_full_sale=True,
                                               previous_position=position,  # 从当前仓位
                                               current_position=0.0)  # 到0%（清仓）
                else:
                    self.logger.info(f"🔴 {code} 清仓操作: {position:.2f}% → 0% | 状态: {ocr_status} | ⚠️ 状态未达标，暂不触发交易")
                
        except Exception as e:
            self.logger.error(f"处理清仓失败 - {code}: {e}")
    
    def trigger_buy_operation(self, code, current_data, position_diff, previous_position, current_position):
        """触发买入操作"""
        try:
            self.logger.info(f"📈 买入信号 {code}: +{position_diff:.2f}% (从{previous_position:.2f}%→{current_position:.2f}%)")
            # 买入金额 = 账户资金 * 仓位差距
            self.execute_trading_action('买入', code, position_diff, previous_position=previous_position, current_position=current_position)
            
        except Exception as e:
            self.logger.error(f"处理买入操作失败 - {code}: {e}")
    
    def trigger_sell_operation(self, code, current_data, position_diff, previous_position, current_position):
        """触发卖出操作"""
        try:
            self.logger.info(f"📉 卖出信号 {code}: -{position_diff:.2f}% (从{previous_position:.2f}%→{current_position:.2f}%)")
            # 卖出金额 = 该股票持仓金额 * 仓位差距
            self.execute_trading_action('卖出', code, position_diff, previous_position=previous_position, current_position=current_position)
            
        except Exception as e:
            self.logger.error(f"处理卖出操作失败 - {code}: {e}")
    
    def execute_trading_action(self, action, code, position_percent, is_full_sale=False, previous_position=None, current_position=None):
        """执行交易动作"""
        try:
            # 防重复检查：检查是否在冷却期内
            if self._is_trade_in_cooldown(code, action, position_percent):
                self.logger.info(f"⏳ {code} 交易在冷却期内，跳过重复操作")
                return
            
            # 计算交易价格和数量
            price_info = self._calculate_trading_price_and_quantity(action, code, position_percent, is_full_sale)
            if not price_info:
                self.logger.error(f"无法计算 {code} {action} 的价格和数量")
                return
            
            trading_price = price_info['price']
            trading_quantity = price_info['quantity'] 
            trading_amount = price_info['amount']
            price_source = price_info['source']
            
            # 🔥 修复：先定义变量，避免NameError
            # 现在API调用已经使用正确数量，所以历史记录也应该记录正确数量
            actual_order_quantity = trading_quantity  # 使用计算出的正确数量
            actual_order_amount = trading_amount  # 使用计算出的正确金额
            
            # 检查是否启用自动交易
            auto_trade = self.config_manager.get('trading.auto_trade', False)
            
            if is_full_sale:
                message = f"执行{action}: {code} (清仓所有持仓)"
            else:
                message = f"执行{action}: {code} (仓位变化: {position_percent:.2f}%)"
            
            # 🔥 修复：显示正确的下单数量和金额
            detailed_message = f"{message}\n订单类型: 市价单 (参考价格: ${trading_price:.2f})\n下单数量: {actual_order_quantity}股\n预估金额: ${actual_order_amount:.2f}"
            
            self.logger.info(f"💰 {detailed_message}")
            
            # 记录此次交易到冷却期（避免重复触发）
            self._record_trade(code, action, position_percent)
            
            # 构建交易信号数据
            signal_action = "BUY" if action == "买入" else "SELL"
            
            # 🔥 修复：检查交易数量，避免0股交易
            if actual_order_quantity <= 0:
                self.logger.warning(f"⚠️ {code} {action} 数量为 {actual_order_quantity}，跳过交易")
                return
                
            # 🔥 修复：添加弹窗所需的完整数据
            account_funds = self.get_current_account_funds()
            
            signal_data = {
                'text': f"{code} {action} {position_percent:.2f}%",
                'confidence': 1.0,  # 来自数据比对的信号，置信度为1.0
                'stock_code': code,
                'action': action,
                'position_change': position_percent,
                'is_full_sale': is_full_sale,
                'message': message,
                'detailed_message': detailed_message,
                'trading_price': trading_price,
                'trading_quantity': actual_order_quantity,  # 🔥 使用实际下单数量
                'trading_amount': actual_order_amount,  # 🔥 使用实际下单金额
                'price_source': price_source,
                'previous_position': previous_position,
                'current_position': current_position,
                # 🔥 新增：弹窗计算公式所需的数据
                'account_funds': account_funds,
                'calculation_type': price_info.get('calculation_type', ''),
                'monitor_position': price_info.get('monitor_position', 0),
                'own_position': price_info.get('own_position', 0),
                'own_market_price': price_info.get('own_market_price', 0),
                'monitor_cost_price': price_info.get('monitor_cost_price', 0)
            }
            
            # 将交易信号添加到收集列表（而不是直接发送）
            self.current_trading_signals.append({
                'action': signal_action,
                'data': signal_data
            })
            
            # 🔥 统一记录完整的交易历史（避免重复记录）
            account_funds = self.get_current_account_funds()
            
            # 🔥 详细计算日志 - 最终下单信息
            if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                self.config_manager.gui_log_callback("INFO", f"🎯 [{code}] 最终下单信息:")
                self.config_manager.gui_log_callback("INFO", f"   📊 下单数量: {actual_order_quantity}股")
                self.config_manager.gui_log_callback("INFO", f"   💰 下单金额: ${actual_order_amount:.2f}")
                self.config_manager.gui_log_callback("INFO", f"   💡 使用计算出的正确数量进行交易")
                self.config_manager.gui_log_callback("INFO", f"   📋 交易历史记录完整的交易信息")
            
            record_id = self.config_manager.add_trading_record(
                stock_code=code,
                direction=action,
                quantity=actual_order_quantity,  # 🔥 使用实际下单数量
                amount=actual_order_amount,      # 🔥 使用实际下单金额
                prev_position=previous_position if previous_position is not None else 0,
                current_position=current_position if current_position is not None else 0,
                position_diff=position_percent if action == "买入" else -position_percent,
                account_funds=account_funds,
                ocr_status="全部成交"  # 默认状态
            )
            
            # 添加到操作历史（pending状态，等待用户确认）
            self.add_history_record(
                f"交易信号-{action}",
                f"{code} - 市价单, 数量:{actual_order_quantity}股, 预估金额:${actual_order_amount:.2f}",
                "success" if auto_trade else "pending"
            )
                
        except Exception as e:
            self.logger.error(f"执行交易动作失败 - {action} {code}: {e}")
    
    def process_collected_trading_signals(self):
        """处理收集到的交易信号 - 批量发送"""
        try:
            if not self.current_trading_signals:
                self.logger.info("本轮比对无交易信号")
                return
            
            signal_count = len(self.current_trading_signals)
            
            if signal_count == 1:
                # 单笔交易，直接发送
                signal = self.current_trading_signals[0]
                self.logger.info(f"📤 发送单笔交易信号: {signal['data']['stock_code']} {signal['data']['action']}")
                self.trading_signal.emit(signal['action'], signal['data'])
            else:
                # 多笔交易，发送批量信号
                stock_codes = [signal['data']['stock_code'] for signal in self.current_trading_signals]
                self.logger.info(f"📤 发送批量交易信号: {signal_count}笔交易 - 股票: {', '.join(stock_codes)}")
                
                # 构建批量交易信号数据
                batch_signal_data = {
                    'is_batch': True,
                    'signal_count': signal_count,
                    'stock_codes': stock_codes,
                    'signals': self.current_trading_signals,
                    'primary_signal': self.current_trading_signals[0]['data']  # 第一笔交易作为主信号
                }
                
                # 发送批量交易信号
                self.trading_signal.emit('BATCH', batch_signal_data)
                
        except Exception as e:
            self.logger.error(f"处理收集的交易信号失败: {e}")
    
    def _calculate_trading_price_and_quantity(self, action, code, position_percent, is_full_sale):
        """计算交易价格和数量"""
        try:
            if action == "买入":
                return self._calculate_buy_price_and_quantity(code, position_percent)
            else:  # 卖出
                return self._calculate_sell_price_and_quantity(code, position_percent, is_full_sale)
        except Exception as e:
            self.logger.error(f"计算 {action} 价格数量失败 - {code}: {e}")
            return None
    
    def _calculate_buy_price_and_quantity(self, code, position_percent):
        """计算买入价格和数量（新逻辑：区分新买入和加仓）"""
        try:
            # 获取监控组合数据（OCR识别的）
            monitor_data = None
            for data in self.market_data_list:
                if data.get('代码', '') == code:
                    monitor_data = data
                    break
            
            if not monitor_data:
                raise Exception(f"无法从监控组合获取 {code} 的数据")
            
            # 获取监控组合成本价
            monitor_cost_price_str = monitor_data.get('成本价', '').replace('$', '').replace(',', '').strip()
            monitor_cost_price = float(monitor_cost_price_str)
            
            # 获取监控组合仓位比例
            monitor_position_str = monitor_data.get('仓位比例', '').replace('%', '').strip()
            monitor_position = float(monitor_position_str)
            
            # 获取自有组合信息
            own_info = self._get_own_stock_info(code)
            own_position = own_info['position_ratio']  # 自有组合仓位比例
            own_market_price = own_info['market_price']  # 自有组合市价
            
            # 获取配置的买单价格偏移
            buy_price_offset = self.config_manager.get('trading.buy_price_offset', 0.5)
            
            # 获取自有账户总资产
            total_assets = self._get_account_funds()
            
            # 🔥 详细计算日志 - 输入参数
            if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                self.config_manager.gui_log_callback("INFO", f"💰 [{code}] 买入计算 - 输入参数:")
                self.config_manager.gui_log_callback("INFO", f"   📊 监控组合仓位: {monitor_position:.2f}%")
                self.config_manager.gui_log_callback("INFO", f"   📊 监控组合成本价: ${monitor_cost_price:.3f}")
                self.config_manager.gui_log_callback("INFO", f"   📊 自有组合仓位: {own_position:.2f}%")
                self.config_manager.gui_log_callback("INFO", f"   📊 自有组合市价: ${own_market_price:.3f}")
                self.config_manager.gui_log_callback("INFO", f"   💰 账户总资产: ${total_assets:,.0f}")
                self.config_manager.gui_log_callback("INFO", f"   ⚙️ 买单价格偏移: +${buy_price_offset:.1f}")
            
            # 🔥 资金检查：确保账户资金不为0
            if total_assets <= 0:
                self.logger.error(f"❌ {code} 账户资金不足或获取失败: ${total_assets}，无法计算交易数量")
                if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                    self.config_manager.gui_log_callback("ERROR", f"❌ [{code}] 账户资金不足: ${total_assets}")
                return None
            
            # 判断买入类型并计算价格数量
            if own_position == 0:
                # 一、仓位增加 - 1. 从0%增加（新买入）
                # 价格：监控组合成本价 + 买单偏移
                buy_price = monitor_cost_price + buy_price_offset
                
                # 🔥 详细计算日志 - 新买入
                if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                    self.config_manager.gui_log_callback("INFO", f"🆕 [{code}] 新买入计算 (从0%开始):")
                    self.config_manager.gui_log_callback("INFO", f"   💰 买入价格 = 监控成本价 + 偏移 = ${monitor_cost_price:.3f} + ${buy_price_offset:.1f} = ${buy_price:.2f}")
            
                # 计算过程调试
                raw_calc = (monitor_position / 100.0) * total_assets / monitor_cost_price
                
                # 🔥 详细计算日志 - 数量计算
                if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                    self.config_manager.gui_log_callback("INFO", f"   📊 数量计算公式: (监控仓位% ÷ 100) × 总资产 ÷ 监控成本价")
                    self.config_manager.gui_log_callback("INFO", f"   📊 = ({monitor_position:.2f} ÷ 100) × ${total_assets:,.0f} ÷ ${monitor_cost_price:.3f}")
                    self.config_manager.gui_log_callback("INFO", f"   📊 = {monitor_position/100:.4f} × ${total_assets:,.0f} ÷ ${monitor_cost_price:.3f} = {raw_calc:.2f}股")
                
                # 🔥 修复：防止数量为0的问题
                if raw_calc < 1.0:
                    if raw_calc >= 0.5:
                        quantity = 1  # 如果大于0.5股，向上取整为1股
                        self.logger.warning(f"⚠️ {code} 计算数量{raw_calc:.2f}股不足1股，已调整为1股")
                        if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                            self.config_manager.gui_log_callback("WARNING", f"   ⚠️ 计算结果{raw_calc:.2f}股 → 向上调整为1股")
                    else:
                        quantity = 0  # 如果小于0.5股，说明资金严重不足
                        self.logger.error(f"❌ {code} 资金不足！仅可买入{raw_calc:.2f}股，建议增加资金或降低仓位目标")
                        if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                            self.config_manager.gui_log_callback("ERROR", f"   ❌ 计算结果{raw_calc:.2f}股 → 资金不足，无法下单")
                else:
                    quantity = int(raw_calc)
                    if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                        self.config_manager.gui_log_callback("INFO", f"   ✅ 计算结果{raw_calc:.2f}股 → 取整为{quantity}股")
                
                actual_amount = quantity * buy_price
                price_source = f"监控成本价${monitor_cost_price:.3f} + 偏移${buy_price_offset:.1f}"
                
                # 🔥 详细计算日志 - 最终结果
                if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                    self.config_manager.gui_log_callback("INFO", f"   🎯 最终结果: {quantity}股 × ${buy_price:.2f} = ${actual_amount:.2f}")
                
                self.logger.info(f"💰 新买入计算：{monitor_position:.2f}% × ${total_assets:.0f} ÷ ${monitor_cost_price:.3f} = {quantity}股")
                
            else:
                # 一、仓位增加 - 2. 从非0%增加（加仓）
                # 价格：自有组合市价 + 买单偏移
                buy_price = own_market_price + buy_price_offset
                # 数量：(监控组合仓位% - 自有组合仓位%) × 自有总资产 ÷ 自有组合市价  
                position_diff = abs(monitor_position - own_position)  # 🔥 修复：使用绝对值避免负数
                
                # 🔥 详细计算日志 - 加仓
                if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                    self.config_manager.gui_log_callback("INFO", f"📈 [{code}] 加仓计算 (从{own_position:.2f}%增加):")
                    self.config_manager.gui_log_callback("INFO", f"   💰 买入价格 = 自有市价 + 偏移 = ${own_market_price:.3f} + ${buy_price_offset:.1f} = ${buy_price:.2f}")
                    self.config_manager.gui_log_callback("INFO", f"   📊 仓位差异 = |监控仓位 - 自有仓位| = |{monitor_position:.2f}% - {own_position:.2f}%| = {position_diff:.2f}%")
                
                raw_calc = (position_diff / 100.0) * total_assets / own_market_price
                
                # 🔥 详细计算日志 - 数量计算
                if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                    self.config_manager.gui_log_callback("INFO", f"   📊 数量计算公式: (仓位差异% ÷ 100) × 总资产 ÷ 自有市价")
                    self.config_manager.gui_log_callback("INFO", f"   📊 = ({position_diff:.2f} ÷ 100) × ${total_assets:,.0f} ÷ ${own_market_price:.3f}")
                    self.config_manager.gui_log_callback("INFO", f"   📊 = {position_diff/100:.4f} × ${total_assets:,.0f} ÷ ${own_market_price:.3f} = {raw_calc:.2f}股")
                
                # 🔥 修复：防止加仓数量为0的问题
                if raw_calc < 1.0:
                    if raw_calc >= 0.5:
                        quantity = 1  # 如果大于0.5股，向上取整为1股
                        self.logger.warning(f"⚠️ {code} 加仓计算数量{raw_calc:.2f}股不足1股，已调整为1股")
                        if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                            self.config_manager.gui_log_callback("WARNING", f"   ⚠️ 计算结果{raw_calc:.2f}股 → 向上调整为1股")
                    else:
                        quantity = 0  # 如果小于0.5股，说明资金或仓位差异太小
                        self.logger.error(f"❌ {code} 加仓数量太小！仅需加仓{raw_calc:.2f}股，建议增加资金或等待更大的仓位变化")
                        if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                            self.config_manager.gui_log_callback("ERROR", f"   ❌ 计算结果{raw_calc:.2f}股 → 仓位差异太小，无法下单")
                else:
                    quantity = int(raw_calc)
                    if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                        self.config_manager.gui_log_callback("INFO", f"   ✅ 计算结果{raw_calc:.2f}股 → 取整为{quantity}股")
                
                actual_amount = quantity * buy_price
                price_source = f"自有市价${own_market_price:.3f} + 偏移${buy_price_offset:.1f}"
                
                # 🔥 详细计算日志 - 最终结果
                if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                    self.config_manager.gui_log_callback("INFO", f"   🎯 最终结果: {quantity}股 × ${buy_price:.2f} = ${actual_amount:.2f}")
                
                self.logger.info(f"💰 加仓计算：({monitor_position:.2f}% - {own_position:.2f}%) × ${total_assets:.0f} ÷ ${own_market_price:.3f} = {quantity}股")
                self.logger.info(f"💰 详细公式：({position_diff:.2f}/100) × {total_assets:.0f} ÷ {own_market_price:.3f} = {raw_calc:.2f} → int({quantity})股")
            
            return {
                'price': buy_price,
                'quantity': quantity,
                'amount': actual_amount,
                'source': price_source,
                'calculation_type': '新买入' if own_position == 0 else '加仓',
                'monitor_position': monitor_position,
                'own_position': own_position,
                # 🔥 新增：弹窗公式显示所需的字段
                'own_market_price': own_market_price,
                'monitor_cost_price': monitor_cost_price
            }
            
        except Exception as e:
            self.logger.error(f"计算买入价格失败 - {code}: {e}")
            return None
    
    def _calculate_sell_price_and_quantity(self, code, position_percent, is_full_sale):
        """计算卖出价格和数量（新逻辑：区分清仓和减仓）"""
        try:
            # 获取监控组合数据（OCR识别的）
            monitor_data = None
            for data in self.market_data_list:
                if data.get('代码', '') == code:
                    monitor_data = data
                    break
            
            if not monitor_data:
                raise Exception(f"无法从监控组合获取 {code} 的数据")
            
            # 获取监控组合仓位比例
            monitor_position_str = monitor_data.get('仓位比例', '').replace('%', '').strip()
            monitor_position = float(monitor_position_str)
            
            # 获取自有组合信息
            own_info = self._get_own_stock_info(code)
            own_position = own_info['position_ratio']  # 自有组合仓位比例
            own_market_price = own_info['market_price']  # 自有组合市价
            own_quantity = own_info['quantity']  # 自有组合持仓数量
            
            if own_market_price <= 0:
                raise Exception(f"无法获取 {code} 的自有组合市价")
            
            # 获取配置的卖单价格偏移
            sell_price_offset = self.config_manager.get('trading.sell_price_offset', 0.5)
            
            # 获取自有账户总资产
            total_assets = self._get_account_funds()
            

            
            # 🔥 资金检查：确保账户资金不为0（用于减仓计算）
            if total_assets <= 0:
                self.logger.warning(f"⚠️ {code} 账户资金获取失败: ${total_assets}，减仓计算可能不准确")
                if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                    self.config_manager.gui_log_callback("WARNING", f"   ⚠️ 账户资金获取失败，减仓计算可能不准确")
            
            # 卖出价格：自有组合市价 - 卖单偏移
            sell_price = own_market_price - sell_price_offset
            
            # 🔥 详细计算日志 - 卖出价格
            if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                self.config_manager.gui_log_callback("INFO", f"   💰 卖出价格 = 自有市价 - 偏移 = ${own_market_price:.3f} - ${sell_price_offset:.1f} = ${sell_price:.2f}")
            
            # 判断卖出类型并计算数量
            if monitor_position == 0:
                # 二、仓位减少 - 1. 减少到0%（清仓）
                # 数量：全部持仓数量
                quantity = own_quantity
                actual_amount = quantity * sell_price
                calculation_type = "清仓"
                
                # 🔥 详细计算日志 - 清仓
                if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                    self.config_manager.gui_log_callback("INFO", f"🔴 [{code}] 清仓计算 (卖出到0%):")
                    self.config_manager.gui_log_callback("INFO", f"   📊 卖出数量 = 全部持仓 = {quantity}股")
                    self.config_manager.gui_log_callback("INFO", f"   🎯 最终结果: {quantity}股 × ${sell_price:.2f} = ${actual_amount:.2f}")
                
                self.logger.info(f"💰 清仓计算：卖出全部 {quantity} 股")
                
            else:
                # 二、仓位减少 - 2. 减少到非0%（减仓）
                # 数量：(自有组合仓位% - 监控组合仓位%) × 自有总资产 ÷ 自有组合市价
                position_diff = abs(own_position - monitor_position)  # 🔥 修复：使用绝对值避免负数
                
                # 🔥 详细计算日志 - 减仓
                if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                    self.config_manager.gui_log_callback("INFO", f"📉 [{code}] 减仓计算 (从{own_position:.2f}%减少):")
                    self.config_manager.gui_log_callback("INFO", f"   📊 仓位差异 = |自有仓位 - 监控仓位| = |{own_position:.2f}% - {monitor_position:.2f}%| = {position_diff:.2f}%")
                
                raw_calc = (position_diff / 100.0) * total_assets / own_market_price
                
                # 🔥 详细计算日志 - 数量计算
                if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                    self.config_manager.gui_log_callback("INFO", f"   📊 数量计算公式: (仓位差异% ÷ 100) × 总资产 ÷ 自有市价")
                    self.config_manager.gui_log_callback("INFO", f"   📊 = ({position_diff:.2f} ÷ 100) × ${total_assets:,.0f} ÷ ${own_market_price:.3f}")
                    self.config_manager.gui_log_callback("INFO", f"   📊 = {position_diff/100:.4f} × ${total_assets:,.0f} ÷ ${own_market_price:.3f} = {raw_calc:.2f}股")
                
                # 🔥 修复：防止卖出数量为0或负数的问题
                if raw_calc <= 0:
                    # 如果计算结果为负数或零，说明不需要减仓
                    quantity = 0
                    self.logger.error(f"❌ {code} 卖出计算异常！计算结果{raw_calc:.2f}股，不需要减仓")
                    if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                        self.config_manager.gui_log_callback("ERROR", f"   ❌ 计算结果{raw_calc:.2f}股 → 数量异常，无法下单")
                elif raw_calc < 1.0:
                    if raw_calc >= 0.5:
                        quantity = 1  # 如果大于0.5股，向上取整为1股
                        self.logger.warning(f"⚠️ {code} 卖出计算数量{raw_calc:.2f}股不足1股，已调整为1股")
                        if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                            self.config_manager.gui_log_callback("WARNING", f"   ⚠️ 计算结果{raw_calc:.2f}股 → 向上调整为1股")
                    else:
                        quantity = 0  # 如果小于0.5股，数量太小不值得交易
                        self.logger.error(f"❌ {code} 卖出数量太小！仅需卖出{raw_calc:.2f}股，建议忽略此次减仓")
                        if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                            self.config_manager.gui_log_callback("ERROR", f"   ❌ 计算结果{raw_calc:.2f}股 → 数量太小，无法下单")
                else:
                    quantity = int(raw_calc)
                    if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                        self.config_manager.gui_log_callback("INFO", f"   ✅ 计算结果{raw_calc:.2f}股 → 取整为{quantity}股")
                
                # 确保不卖出超过实际持仓
                if quantity > own_quantity:
                    quantity = own_quantity
                    self.logger.warning(f"⚠️ {code} 卖出数量超过持仓，已调整为全部持仓{quantity}股")
                    if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                        self.config_manager.gui_log_callback("WARNING", f"   ⚠️ 计算数量{raw_calc:.0f}股 > 持仓{own_quantity}股 → 调整为{quantity}股")
                
                actual_amount = quantity * sell_price
                calculation_type = "减仓"
                
                # 🔥 详细计算日志 - 最终结果
                if hasattr(self.config_manager, 'gui_log_callback') and self.config_manager.gui_log_callback:
                    self.config_manager.gui_log_callback("INFO", f"   🎯 最终结果: {quantity}股 × ${sell_price:.2f} = ${actual_amount:.2f}")
                
                self.logger.info(f"💰 减仓计算：({own_position:.2f}% - {monitor_position:.2f}%) × ${total_assets:.0f} ÷ ${own_market_price:.3f} = {quantity}股")
            
            price_source = f"自有市价${own_market_price:.3f} - 偏移${sell_price_offset:.1f}"
            
            return {
                'price': sell_price,
                'quantity': quantity,
                'amount': actual_amount,
                'source': price_source,
                'calculation_type': calculation_type,
                'monitor_position': monitor_position,
                'own_position': own_position,
                # 🔥 新增：弹窗公式显示所需的字段
                'own_market_price': own_market_price,
                'own_holding_quantity': own_quantity
            }
            
        except Exception as e:
            self.logger.error(f"计算卖出价格失败 - {code}: {e}")
            return None
    
    def _get_account_funds(self):
        """获取账户总资产（用于交易计算，统一使用美元）"""
        try:
            # 优先使用选中账户的资金信息
            current_data = self.account_combo.currentData()
            if current_data:
                total_assets = current_data.get('total_assets', 0.0)
                broker_name = current_data.get('broker_name', '')
                currency = current_data.get('currency', 'USD')
                acc_id = current_data.get('acc_id', 'N/A')
                
                print(f"🔍 [资金调试] 账户数据源: currentData()")
                print(f"🔍 [资金调试] 账户ID: {acc_id}")
                print(f"🔍 [资金调试] 券商名称: '{broker_name}'")
                print(f"🔍 [资金调试] 币种: '{currency}'")
                print(f"🔍 [资金调试] 原始资金: {total_assets:,.2f}")
                self.logger.info(f"🔍 [资金调试] 账户数据源: currentData()")
                self.logger.info(f"🔍 [资金调试] 账户ID: {acc_id}")
                self.logger.info(f"🔍 [资金调试] 券商名称: '{broker_name}'")
                self.logger.info(f"🔍 [资金调试] 币种: '{currency}'")
                self.logger.info(f"🔍 [资金调试] 原始资金: {total_assets:,.2f}")
                
                if total_assets > 0:
                    # 🔥 修复：BrokerAccountScanner已经进行了汇率转换，这里直接使用
                    currency = current_data.get('currency', 'USD')
                    market = current_data.get('market')
                    
                    print(f"🔍 [资金调试] 账户资金已转换完成: {total_assets:,.2f} {currency}")
                    print(f"🔍 [资金调试] 市场类型: {market}")
                    print(f"🔍 [资金调试] 币种: {currency}")
                    self.logger.info(f"🔍 [资金调试] 账户资金已转换完成: {total_assets:,.2f} {currency}")
                    self.logger.info(f"🔍 [资金调试] 市场类型: {market}")  
                    self.logger.info(f"🔍 [资金调试] 币种: {currency}")
                    
                    # 🔥 直接返回BrokerAccountScanner转换后的金额（美股=USD，港股=HKD）
                    return total_assets
            
            # 备选方案：从FutuTrader获取  
            self.logger.info(f"🔍 [资金调试] 使用备选方案: FutuTrader API")
            print(f"🔍 [资金调试] 使用备选方案: FutuTrader API")
            from trading.futu_trader import FutuTrader
            futu_trader = FutuTrader(self.config_manager)
            
            current_acc_id = self.get_current_acc_id()
            if current_acc_id:
                self.logger.info(f"🔍 [资金调试] 通过API查询账户: {current_acc_id}")
                print(f"🔍 [资金调试] 通过API查询账户: {current_acc_id}")
                funds_info = futu_trader.get_account_funds(current_acc_id)
                # 🔥 修复：FutuTrader.get_account_funds也已经进行了汇率转换，直接使用
                total_assets = funds_info.get('total_assets', 3898.0)  # 默认美元金额
                print(f"🔍 [资金调试] API资金（已转换）: ${total_assets:,.2f} USD")
                self.logger.info(f"🔍 [资金调试] API资金（已转换）: ${total_assets:,.2f} USD")
                return total_assets
            
            # 默认值（美元）
            print(f"🔍 [资金调试] 使用默认值: $3,898.00 (无法获取账户数据)")
            self.logger.info(f"🔍 [资金调试] 使用默认值: $3,898.00 (无法获取账户数据)")
            return 3898.0
            
        except Exception as e:
            self.logger.error(f"获取账户总资产失败: {e}")
            print(f"🔍 [资金调试] 使用默认值: $3,898.00 (异常处理)")
            self.logger.info(f"🔍 [资金调试] 使用默认值: $3,898.00 (异常处理)")
            return 3898.0
    
    def _get_stock_holding_amount(self, code):
        """获取特定股票的持仓金额"""
        try:
            from trading.futu_trader import FutuTrader
            futu_trader = FutuTrader(self.config_manager)
            
            # TODO: 这里需要实现从FutuTrader获取持仓金额的方法
            # 暂时返回固定值作为备选
            return 2000.0  # 假设该股票持仓$2000
            
        except Exception as e:
            self.logger.error(f"获取 {code} 持仓金额失败: {e}")
            return 0.0
    
    def _get_real_positions_from_futu(self, futu_trader, target_code):
        """从富途交易接口获取真实持仓数据"""
        try:
            # 🔥 获取真实持仓数据
            self.logger.info(f"🔗 连接富途交易接口获取 {target_code} 持仓...")
            
            # 连接富途交易接口
            if not futu_trader.connect():
                raise Exception("无法连接富途交易接口")
                
            # 获取账户总资产
            account_info = futu_trader.get_account_info()
            # 🔥 修复：添加None检查，避免NoneType错误
            if account_info is None:
                raise Exception("富途API返回空数据，可能是连接问题或API限制")
            if not account_info.get('success', False):
                raise Exception(f"获取账户信息失败: {account_info.get('message', '未知错误')}")
            
            total_assets = account_info.get('total_assets', 0)
            if total_assets <= 0:
                raise Exception(f"账户总资产异常: ${total_assets}")
                
            # 获取所有持仓
            all_positions = futu_trader.get_positions()
            
            # 筛选目标股票的持仓
            target_positions = []
            
            # 🔥 修复：添加None检查，避免NoneType错误
            if all_positions is None:
                self.logger.warning(f"{target_code}: 持仓数据为空")
                return []
            
            for position in all_positions:
                # 🔥 修复：检查position是否为None
                if position is None:
                    self.logger.warning(f"跳过空的持仓记录")
                    continue
                    
                stock_code = position.get('code', '')
                # 处理不同格式的股票代码（如 US.BABA, BABA）
                if self._is_same_stock_code(stock_code, target_code):
                    # 计算持仓比例
                    market_value = position.get('market_value', 0)
                    position_ratio = (market_value / total_assets) * 100 if total_assets > 0 else 0
                    
                    target_positions.append({
                        'code': target_code,
                        'position_ratio': position_ratio,
                        'market_price': position.get('current_price', 100.0),
                        'quantity': position.get('quantity', 0),
                        'market_value': market_value
                    })
                    
                    # 🔥 新增：详细日志显示匹配的持仓
                    self.logger.info(f"✅ 找到匹配持仓: {stock_code} -> {target_code}")
                    self.logger.info(f"   💰 市值: ${market_value:,.2f}, 比例: {position_ratio:.2f}%")
                    self.logger.info(f"   📊 数量: {position.get('quantity', 0)}股, 价格: ${position.get('current_price', 0):.2f}")
                    
            return target_positions
            
        except Exception as e:
            self.logger.error(f"从富途获取 {target_code} 持仓失败: {e}")
            return []
            
    def _is_same_stock_code(self, code1, code2):
        """判断两个股票代码是否为同一股票（处理不同格式）"""
        try:
            # 移除前缀（如 US.BABA -> BABA）
            clean_code1 = code1.split('.')[-1].upper()
            clean_code2 = code2.split('.')[-1].upper()
            return clean_code1 == clean_code2
        except:
            return False
    
    def _load_initial_positions_cache(self, codes_to_cache=None):
        """加载初始持仓信息到缓存（只在第一次调用）"""
        try:
            if self.initial_positions_loaded:
                self.logger.info("✅ 初始持仓已加载，跳过重复加载")
                return
                
            import time
            from trading.futu_trader import FutuTrader
            futu_trader = FutuTrader(self.config_manager)
            
            self.logger.info("🔍 初次启动 - 正在加载持仓信息到缓存...")
            
            # 如果没有指定股票代码，获取所有持仓
            if codes_to_cache is None:
                codes_to_cache = []
                # 从富途获取所有持仓的股票代码
                try:
                    all_positions = self._get_real_positions_from_futu(futu_trader)
                    codes_to_cache = [pos.get('code', '') for pos in all_positions if pos.get('code')]
                    self.logger.info(f"🔍 从富途获取到 {len(codes_to_cache)} 只持仓股票: {codes_to_cache}")
                except Exception as e:
                    self.logger.warning(f"⚠️ 获取持仓股票列表失败: {e}，将在运行时动态加载")
                    codes_to_cache = []
            
            # 缓存指定股票的持仓信息
            current_time = time.time()
            for code in codes_to_cache:
                try:
                    positions = self._get_real_positions_from_futu(futu_trader, code)
                    if positions:
                        position_info = positions[0]
                        self.cached_positions[code] = {
                            'position_ratio': position_info['position_ratio'],
                            'market_price': position_info['market_price'],
                            'quantity': position_info['quantity'],
                            'timestamp': current_time
                        }
                        self.logger.info(f"✅ 缓存 {code} 持仓: {position_info['position_ratio']:.2f}%, {position_info['quantity']}股")
                    else:
                        # 无持仓也要缓存，避免重复查询
                        self.cached_positions[code] = {
                            'position_ratio': 0.0,
                            'market_price': 100.0,
                            'quantity': 0,
                            'timestamp': current_time
                        }
                        self.logger.info(f"✅ 缓存 {code} 持仓: 无持仓")
                except Exception as e:
                    self.logger.warning(f"⚠️ 缓存 {code} 持仓失败: {e}")
                    continue
                    
            self.initial_positions_loaded = True
            self.logger.info(f"✅ 初始持仓缓存完成，共缓存 {len(self.cached_positions)} 只股票")
            
        except Exception as e:
            self.logger.error(f"❌ 加载初始持仓缓存失败: {e}")
            
    def _get_cached_position_info(self, code):
        """从缓存获取持仓信息，如果缓存过期或不存在则按需加载"""
        try:
            import time
            current_time = time.time()
            
            # 检查缓存是否存在且有效
            if code in self.cached_positions:
                cache_data = self.cached_positions[code]
                if current_time - cache_data['timestamp'] < self.position_cache_time:
                    # 缓存有效，直接返回
                    self.logger.info(f"✅ {code} 使用缓存持仓: {cache_data['position_ratio']:.2f}%, {cache_data['quantity']}股")
                    return {
                        'position_ratio': cache_data['position_ratio'],
                        'market_price': cache_data['market_price'],
                        'quantity': cache_data['quantity']
                    }
            
            # 缓存无效或不存在，重新获取并更新缓存
            self.logger.info(f"🔍 {code} 缓存无效，重新获取持仓信息...")
            stock_info = self._get_own_stock_info_direct(code)
            
            # 更新缓存
            if stock_info:
                self.cached_positions[code] = {
                    'position_ratio': stock_info['position_ratio'],
                    'market_price': stock_info['market_price'],
                    'quantity': stock_info['quantity'],
                    'timestamp': current_time
                }
            
            return stock_info
            
        except Exception as e:
            self.logger.error(f"❌ 获取缓存持仓信息失败: {e}")
            return {
                'position_ratio': 0.0,
                'market_price': 100.0,
                'quantity': 0
            }

    def _get_own_stock_info_direct(self, code):
        """直接获取自有股票持仓信息（不使用缓存）"""
        try:
            from trading.futu_trader import FutuTrader
            futu_trader = FutuTrader(self.config_manager)
            
            # 🔥 修复：获取真实持仓数据
            self.logger.info(f"🔍 正在直接获取 {code} 的真实持仓信息...")
            
            # 获取所有持仓列表
            positions = self._get_real_positions_from_futu(futu_trader, code)
            
            if positions:
                position_info = positions[0]  # 获取第一个匹配的持仓
                position_ratio = position_info['position_ratio']
                market_price = position_info['market_price']
                quantity = position_info['quantity']
                
                # 🔥 详细日志：显示持仓信息
                self.logger.info(f"✅ {code} 真实持仓信息:")
                self.logger.info(f"   📊 持仓比例: {position_ratio:.2f}%")
                self.logger.info(f"   💰 当前市价: ${market_price:.3f}")
                self.logger.info(f"   📦 持仓数量: {quantity}股")
                
                return {
                    'position_ratio': position_ratio, 
                    'market_price': market_price, 
                    'quantity': quantity
                }
            else:
                # 没有持仓，获取市价用于交易计算
                market_price = self._get_market_price_from_ocr(code)
                if market_price <= 0:
                    market_price = 100.0  # 默认值
                    
                # 🔥 详细日志：显示无持仓信息
                self.logger.info(f"✅ {code} 真实持仓信息:")
                self.logger.info(f"   📊 持仓比例: 0.00% (无持仓)")
                self.logger.info(f"   💰 参考市价: ${market_price:.3f}")
                self.logger.info(f"   📦 持仓数量: 0股")
                    
                return {'position_ratio': 0.0, 'market_price': market_price, 'quantity': 0}
                
        except Exception as e:
            self.logger.error(f"直接获取 {code} 自有持仓信息失败: {e}")
            # 🔥 修复：即使异常也尝试从OCR获取市价，避免返回0.0
            try:
                market_price = self._get_market_price_from_ocr(code)
                if market_price > 0:
                    return {'position_ratio': 0.0, 'market_price': market_price, 'quantity': 0}
            except:
                pass
            return {'position_ratio': 0.0, 'market_price': 100.0, 'quantity': 0}

    def _get_own_stock_info(self, code):
        """获取自有股票持仓信息（使用缓存优化）"""
        # 🔥 优化：优先使用缓存，避免频繁API调用
        return self._get_cached_position_info(code)
    
    def _get_market_price_from_ocr(self, code):
        """从OCR数据中获取股票的最新价"""
        try:
            if not hasattr(self, 'market_data_list') or not self.market_data_list:
                return 0.0
            
            for data in self.market_data_list:
                if data.get('代码', '') == code:
                    price_str = data.get('最新价', '').replace('$', '').replace(',', '').strip()
                    if price_str:
                        return float(price_str)
            
            return 0.0
            
        except Exception as e:
            self.logger.error(f"从OCR获取 {code} 最新价失败: {e}")
            return 0.0
    
    def _is_trade_in_cooldown(self, code, action, position_percent):
        """检查交易是否在冷却期内（防重复）"""
        try:
            import time
            
            current_time = time.time()
            
            # 🔥 新增：检查失败惩罚冷却期
            if self._is_in_failure_penalty(code, current_time):
                return True
            
            # 检查正常交易冷却期
            if code not in self.recent_trades:
                return False
                
            trade_record = self.recent_trades[code]
            time_diff = current_time - trade_record['timestamp']
            
            if time_diff < self.trade_cooldown:
                self.logger.info(f"⏳ {code} 在正常冷却期内: {action} {position_percent:.2f}% (距离上次 {time_diff:.1f}s < {self.trade_cooldown}s)")
                return True
            else:
                self.logger.info(f"✅ {code} 超出冷却期，允许执行: {action} {position_percent:.2f}% (距离上次 {time_diff:.1f}s)")
            
            return False
            
        except Exception as e:
            self.logger.error(f"检查交易冷却失败 - {code}: {e}")
            return False
            
    def _is_in_failure_penalty(self, code, current_time):
        """检查是否在失败惩罚期内"""
        try:
            if code not in self.failed_trades:
                return False
                
            failure_record = self.failed_trades[code]
            time_since_failure = current_time - failure_record['last_failure']
            
            # 如果连续失败3次或以上，执行惩罚冷却
            if failure_record['count'] >= 3 and time_since_failure < self.failure_penalty_time:
                remaining_time = self.failure_penalty_time - time_since_failure
                self.logger.warning(f"🚫 {code} 在失败惩罚期内: 连续失败{failure_record['count']}次，还需等待{remaining_time/60:.1f}分钟")
                return True
                
            return False
            
        except Exception as e:
            self.logger.error(f"检查失败惩罚期失败 - {code}: {e}")
            return False
    
    def _record_trade(self, code, action, position_percent):
        """记录交易操作（用于防重复）"""
        try:
            import time
            
            self.recent_trades[code] = {
                'timestamp': time.time(),
                'action': action,
                'position_diff': position_percent
            }
            
            # 🔥 关键修复：交易执行后立即清除持仓缓存，强制重新获取
            if code in self.cached_positions:
                self.logger.info(f"🔄 清除 {code} 持仓缓存，下次将重新获取真实持仓")
                del self.cached_positions[code]
            
            self.logger.info(f"📝 记录交易操作: {code} {action} {position_percent:.2f}%")
            
            # 🔥 新增：交易成功后清除失败记录
            if code in self.failed_trades:
                self.logger.info(f"✅ {code} 交易成功，清除失败记录")
                del self.failed_trades[code]
            
            # 清理过期的交易记录（超过1小时的记录）
            current_time = time.time()
            expired_codes = []
            for trade_code, record in self.recent_trades.items():
                if current_time - record['timestamp'] > 3600:  # 1小时
                    expired_codes.append(trade_code)
                    
            for expired_code in expired_codes:
                del self.recent_trades[expired_code]
                self.logger.info(f"🧹 清理过期交易记录: {expired_code}")
                
        except Exception as e:
            self.logger.error(f"记录交易操作失败 - {code}: {e}")
    
    def record_trade_failure(self, code, action, error_message):
        """记录交易失败（用于惩罚冷却）"""
        try:
            import time
            
            current_time = time.time()
            
            if code not in self.failed_trades:
                self.failed_trades[code] = {
                    'count': 0,
                    'last_failure': 0,
                    'reason': ''
                }
            
            failure_record = self.failed_trades[code]
            
            # 如果距离上次失败超过1小时，重置计数器
            if current_time - failure_record['last_failure'] > 3600:
                failure_record['count'] = 0
            
            # 增加失败计数
            failure_record['count'] += 1
            failure_record['last_failure'] = current_time
            failure_record['reason'] = error_message
            
            self.logger.warning(f"📝 {code} 交易失败记录: 连续失败{failure_record['count']}次 | 原因: {error_message}")
            
            # 如果连续失败达到阈值，启动惩罚冷却
            if failure_record['count'] >= 3:
                penalty_minutes = self.failure_penalty_time / 60
                self.logger.error(f"🚫 {code} 连续失败{failure_record['count']}次，启动惩罚冷却{penalty_minutes}分钟")
            
        except Exception as e:
            self.logger.error(f"记录交易失败失败 - {code}: {e}")
    
    def update_latest_trade_record_status(self, action, details, status):
        """更新最新的交易记录状态（避免重复添加记录）"""
        try:
            # 查找最近的pending状态的交易信号记录
            records = self.config_manager.get('history.records', [])
            
            # 从最新记录开始查找对应的pending记录
            for i in range(len(records) - 1, -1, -1):
                record = records[i]
                if (record.get('action', '').startswith('交易信号-') and 
                    record.get('status') == 'pending'):
                    
                    # 更新记录
                    records[i] = {
                        'timestamp': datetime.now().isoformat(),
                        'action': action,
                        'details': details,
                        'status': status
                    }
                    
                    # 保存更新后的记录
                    self.config_manager.set('history.records', records)
                    self.config_manager.save_config()
                    
                    self.logger.info(f"📝 更新交易记录状态: {action} -> {status}")
                    return
            
            # 如果没找到pending记录，直接添加新记录
            self.add_history_record(action, details, status)
            
        except Exception as e:
            self.logger.error(f"更新交易记录状态失败: {e}")
            # 降级处理：直接添加新记录
            self.add_history_record(action, details, status)
    
    def parse_market_data_from_ocr(self, ocr_result):
        """从OCR结果解析市场数据 - 按8字段规则处理"""
        try:
            market_data = []
            
            # 调试：打印传入数据的结构
            self.logger.info(f"🔍 parse_market_data_from_ocr 接收到的数据类型: {type(ocr_result)}")
            if isinstance(ocr_result, dict):
                keys = list(ocr_result.keys())
                self.logger.info(f"🔍 ocr_result 顶级键: {keys[:10]}...")  # 只显示前10个键
                if 'enhanced_data' in ocr_result:
                    enhanced_keys = list(ocr_result['enhanced_data'].keys()) if isinstance(ocr_result['enhanced_data'], dict) else []
                    self.logger.info(f"🔍 enhanced_data 键: {enhanced_keys}")
                    if 'potential_table_data' in ocr_result['enhanced_data']:
                        table_count = len(ocr_result['enhanced_data']['potential_table_data'])
                        self.logger.info(f"🔍 potential_table_data 行数: {table_count}")
                else:
                    self.logger.warning("🔍 ocr_result 中没有 enhanced_data 键")
            
            # 使用增强数据中的表格结构
            if 'enhanced_data' in ocr_result and 'potential_table_data' in ocr_result['enhanced_data']:
                table_data = ocr_result['enhanced_data']['potential_table_data']
                self.logger.info(f"使用表格结构数据，共 {len(table_data)} 行")
                
                # 验证并解析每行数据
                last_sequence = None  # 上一条数据的序号，初始为None
                
                for row_idx, row in enumerate(table_data):
                    columns = row.get('columns', [])
                    if len(columns) == 8:  # 完整的8字段
                        # 先尝试宽松验证
                        if self._validate_8_field_row_relaxed(columns, last_sequence):
                            row_data = self._parse_8_field_row(columns)
                            if row_data and row_data.get('名称', '').strip():
                                market_data.append(row_data)
                                try:
                                    last_sequence = int(row_data['序号'])  # 更新序号
                                except:
                                    pass  # 序号转换失败也不影响
                                self.logger.info(f"✅ 解析第 {row_idx + 1} 行数据: {row_data['名称']} (序号: {row_data.get('序号', 'N/A')})")
                            else:
                                self.logger.warning(f"❌ 第 {row_idx + 1} 行数据解析失败：名称为空")
                        else:
                            # 宽松验证失败，记录详细信息
                            texts = [col.get('text', '').strip() for col in columns]
                            self.logger.warning(f"❌ 第 {row_idx + 1} 行数据验证失败，跳过: {texts}")
                    elif len(columns) == 7:  # 🔥 新增：7字段数据处理（缺序号）
                        texts = [col.get('text', '').strip() for col in columns]
                        self.logger.info(f"🔍 检测到7字段行: {texts}")
                        
                        # 验证7字段格式：代码 + 名称 + 仓位 + 成本 + 最新 + 盈亏 + 状态
                        field1_is_code = texts[0] and any(c.isalnum() for c in texts[0])
                        field2_is_name = texts[1].strip() != ""
                        field3_is_position = texts[2] and '%' in texts[2]
                        
                        if field1_is_code and field2_is_name and field3_is_position:
                            # 自动补充序号
                            if last_sequence is None:
                                last_sequence = 0  # 如果没有序号基准，从0开始
                            auto_sequence = str(last_sequence + 1)
                            self.logger.info(f"🔢 7字段数据自动补充序号: {auto_sequence} (上一个序号: {last_sequence})")
                            
                            # 解析为数据项
                            row_data = {
                                '序号': auto_sequence,  # 🔥 自动补充序号
                                '代码': texts[0],
                                '名称': texts[1],
                                '仓位比例': texts[2],
                                '成本价': texts[3],
                                '最新价': texts[4],
                                '盈亏比例': texts[5],
                                '状态': texts[6]
                            }
                            
                            # 确保必要字段不为空才添加到结果
                            if row_data.get('名称', '').strip():
                                market_data.append(row_data)
                                last_sequence = int(auto_sequence)  # 更新序号计数器
                                self.logger.info(f"✅ 解析第 {row_idx + 1} 行数据(7字段): {row_data['名称']} (自动序号: {auto_sequence})")
                            else:
                                self.logger.warning(f"❌ 第 {row_idx + 1} 行7字段数据解析失败：名称为空")
                        else:
                            self.logger.warning(f"❌ 第 {row_idx + 1} 行7字段验证失败，跳过: 代码OK={field1_is_code}, 名称OK={field2_is_name}, 仓位OK={field3_is_position}")
                    else:
                        self.logger.warning(f"字段不完整，跳过第 {row_idx + 1} 行：{len(columns)} 个字段")
                
            else:
                # 降级到原始文本处理逻辑
                self.logger.warning("未找到表格结构数据，使用原始文本解析")
                
                # 获取所有识别到的文本，按位置排序
                texts = []
                for key, value in ocr_result.items():
                    text = value.get('rec_txt', '').strip()
                    if text and self._is_valid_ocr_text(text):  # 过滤无效文本
                        bbox = value.get('dt_boxes', [])
                        if bbox and len(bbox) >= 4:
                            # 计算Y坐标和X坐标（用于排序）
                            y_coords = [point[1] for point in bbox]
                            x_coords = [point[0] for point in bbox]
                            avg_y = sum(y_coords) / len(y_coords)
                            avg_x = sum(x_coords) / len(x_coords)
                            texts.append({
                                'text': text, 
                                'y': avg_y, 
                                'x': avg_x,
                                'bbox': bbox
                            })
                
                # 先按Y坐标排序（行），再按X坐标排序（列）
                texts.sort(key=lambda x: (x['y'], x['x']))
                
                # 跳过表头
                data_texts = [t for t in texts if not any(header in t['text'] 
                             for header in ['序号', '代码', '名称', '仓位', '成本', '最新', '盈亏', '状态'])]
                
                # 按8字段规则处理数据
                self.logger.info(f"识别到 {len(data_texts)} 个有效文本，开始按8字段规则解析")
                
                # 🔥 修复：灵活分组，支持7字段或8字段数据
                field_groups = []
                i = 0
                group_idx = 1
                while i < len(data_texts):
                    # 尝试8字段组
                    group_8 = data_texts[i:i+8] if i+8 <= len(data_texts) else []
                    # 尝试7字段组（无序号）
                    group_7 = data_texts[i:i+7] if i+7 <= len(data_texts) else []
                    
                    if len(group_8) == 8 and self._validate_flexible_group(group_8):
                        field_groups.append(group_8)
                        self.logger.info(f"📋 第{group_idx}组: 8字段格式 - {[item['text'] for item in group_8]}")
                        i += 8
                    elif len(group_7) == 7 and self._validate_flexible_group(group_7):
                        field_groups.append(group_7)
                        self.logger.info(f"📋 第{group_idx}组: 7字段格式 - {[item['text'] for item in group_7]}")
                        i += 7
                    else:
                        # 跳过这个字段，尝试下一个
                        i += 1
                        continue
                    group_idx += 1
                
                # 验证并解析每个字段组
                last_sequence = 0  # 上一条数据的序号，初始为0
                for group_idx, group in enumerate(field_groups):
                    # 解析字段组，传递last_sequence用于自动补充序号
                    row_data = self._parse_flexible_group(group, last_sequence)
                    if row_data and row_data.get('名称', '').strip():
                        market_data.append(row_data)
                        try:
                            if '序号' in row_data and row_data['序号']:
                                last_sequence = int(row_data['序号'])  # 更新序号
                        except:
                            pass  # 序号转换失败也不影响
                        self.logger.info(f"✅ 解析第 {group_idx + 1} 组数据: {row_data['名称']} (序号: {row_data.get('序号', 'N/A')})")
                    else:
                        # 记录详细的失败信息
                        texts = [item['text'] for item in group]
                        self.logger.warning(f"❌ 第 {group_idx + 1} 组数据解析失败，跳过: {texts}")
            
            self.logger.info(f"解析完成：共 {len(market_data)} 条有效数据")
            return market_data
            
        except Exception as e:
            self.logger.error(f"解析OCR结果失败: {e}")
            return []
    
    def _validate_8_field_row(self, columns, last_sequence):
        """验证8字段行数据是否符合特征"""
        try:
            if len(columns) != 8:
                self.logger.warning(f"❌ 字段行长度不正确: {len(columns)} != 8")
                return False
            
            # 获取文本内容
            texts = [col.get('text', '').strip() for col in columns]
            self.logger.info(f"🔍 开始验证8字段行: {texts}")
            
            # 验证每个字段的特征
            # 字段1：序号 - 纯数字，且比上一条大1
            if not self._is_sequence_field(texts[0], last_sequence):
                self.logger.warning(f"❌ 字段1验证失败(序号): '{texts[0]}', 期望: {last_sequence + 1}")
                return False
            else:
                self.logger.info(f"✅ 字段1(序号)验证通过: '{texts[0]}'")
            
            # 字段2：代码 - 只包含字母和数字
            if not self._is_code_field(texts[1]):
                self.logger.warning(f"❌ 字段2验证失败(代码): '{texts[1]}'")
                return False
            else:
                self.logger.info(f"✅ 字段2(代码)验证通过: '{texts[1]}'")
            
            # 字段3：名称 - 无特征限制，但不能为空
            if not texts[2].strip():
                self.logger.warning(f"❌ 字段3验证失败(名称): 为空")
                return False
            else:
                self.logger.info(f"✅ 字段3(名称)验证通过: '{texts[2]}'")
            
            # 字段4：仓位比例 - 百分比且不超过100%
            if not self._is_position_ratio_field(texts[3]):
                self.logger.warning(f"❌ 字段4验证失败(仓位比例): '{texts[3]}'")
                return False
            else:
                self.logger.info(f"✅ 字段4(仓位比例)验证通过: '{texts[3]}'")
            
            # 字段5：成本价 - 纯数字，有负数，有小数
            if not self._is_cost_price_field(texts[4]):
                self.logger.warning(f"❌ 字段5验证失败(成本价): '{texts[4]}'")
                return False
            else:
                self.logger.info(f"✅ 字段5(成本价)验证通过: '{texts[4]}'")
            
            # 字段6：最新价 - 纯数字，无负数，有小数
            if not self._is_current_price_field(texts[5]):
                self.logger.warning(f"❌ 字段6验证失败(最新价): '{texts[5]}'")
                return False
            else:
                self.logger.info(f"✅ 字段6(最新价)验证通过: '{texts[5]}'")
            
            # 字段7：盈亏比例 - 百分比，有负数有小数
            if not self._is_profit_loss_field(texts[6]):
                self.logger.warning(f"❌ 字段7验证失败(盈亏比例): '{texts[6]}'")
                return False
            else:
                self.logger.info(f"✅ 字段7(盈亏比例)验证通过: '{texts[6]}'")
            
            # 字段8：状态 - 纯汉字
            if not self._is_status_field(texts[7]):
                self.logger.warning(f"❌ 字段8验证失败(状态): '{texts[7]}'")
                return False
            else:
                self.logger.info(f"✅ 字段8(状态)验证通过: '{texts[7]}'")
            
            self.logger.info(f"🎉 8字段行验证完全通过: {texts}")
            return True
            
        except Exception as e:
            self.logger.error(f"验证8字段行失败: {e}")
            return False
    
    def _validate_8_field_group(self, group, last_sequence):
        """验证8字段组是否符合特征"""
        try:
            if len(group) != 8:
                self.logger.warning(f"❌ 字段组长度不正确: {len(group)} != 8")
                return False
            
            # 获取文本内容
            texts = [item['text'] for item in group]
            self.logger.info(f"🔍 开始验证8字段组: {texts}")
            
            # 验证每个字段的特征
            # 字段1：序号 - 纯数字，且比上一条大1
            if not self._is_sequence_field(texts[0], last_sequence):
                self.logger.warning(f"❌ 字段1验证失败(序号): '{texts[0]}', 期望: {last_sequence + 1}")
                return False
            else:
                self.logger.info(f"✅ 字段1(序号)验证通过: '{texts[0]}'")
            
            # 字段2：代码 - 只包含字母和数字
            if not self._is_code_field(texts[1]):
                self.logger.warning(f"❌ 字段2验证失败(代码): '{texts[1]}'")
                return False
            else:
                self.logger.info(f"✅ 字段2(代码)验证通过: '{texts[1]}'")
            
            # 字段3：名称 - 无特征限制，但不能为空
            if not texts[2].strip():
                self.logger.warning(f"❌ 字段3验证失败(名称): 为空")
                return False
            else:
                self.logger.info(f"✅ 字段3(名称)验证通过: '{texts[2]}'")
            
            # 字段4：仓位比例 - 百分比且不超过100%
            if not self._is_position_ratio_field(texts[3]):
                self.logger.warning(f"❌ 字段4验证失败(仓位比例): '{texts[3]}'")
                return False
            else:
                self.logger.info(f"✅ 字段4(仓位比例)验证通过: '{texts[3]}'")
            
            # 字段5：成本价 - 纯数字，有负数，有小数
            if not self._is_cost_price_field(texts[4]):
                self.logger.warning(f"❌ 字段5验证失败(成本价): '{texts[4]}'")
                return False
            else:
                self.logger.info(f"✅ 字段5(成本价)验证通过: '{texts[4]}'")
            
            # 字段6：最新价 - 纯数字，无负数，有小数
            if not self._is_current_price_field(texts[5]):
                self.logger.warning(f"❌ 字段6验证失败(最新价): '{texts[5]}'")
                return False
            else:
                self.logger.info(f"✅ 字段6(最新价)验证通过: '{texts[5]}'")
            
            # 字段7：盈亏比例 - 百分比，有负数有小数
            if not self._is_profit_loss_field(texts[6]):
                self.logger.warning(f"❌ 字段7验证失败(盈亏比例): '{texts[6]}'")
                return False
            else:
                self.logger.info(f"✅ 字段7(盈亏比例)验证通过: '{texts[6]}'")
            
            # 字段8：状态 - 纯汉字
            if not self._is_status_field(texts[7]):
                self.logger.warning(f"❌ 字段8验证失败(状态): '{texts[7]}'")
                return False
            else:
                self.logger.info(f"✅ 字段8(状态)验证通过: '{texts[7]}'")
            
            self.logger.info(f"🎉 8字段组验证完全通过: {texts}")
            return True
            
        except Exception as e:
            self.logger.error(f"验证8字段组失败: {e}")
            return False
    
    def _parse_8_field_row(self, columns):
        """解析8字段行为市场数据"""
        try:
            texts = [self._clean_text(col.get('text', '')) for col in columns]
            
            return {
                '序号': texts[0],  # OCR识别的序号
                '代码': texts[1],
                '名称': texts[2],
                '仓位比例': texts[3],
                '成本价': texts[4],
                '最新价': texts[5],
                '盈亏比例': texts[6],
                '状态': texts[7]
            }
            
        except Exception as e:
            self.logger.error(f"解析8字段行失败: {e}")
            return None
    
    def _parse_8_field_group(self, group):
        """解析8字段组为市场数据"""
        try:
            texts = [self._clean_text(item['text']) for item in group]
            
            return {
                '序号': texts[0],  # OCR识别的序号
                '代码': texts[1],
                '名称': texts[2],
                '仓位比例': texts[3],
                '成本价': texts[4],
                '最新价': texts[5],
                '盈亏比例': texts[6],
                '状态': texts[7]
            }
            
        except Exception as e:
            self.logger.error(f"解析8字段组失败: {e}")
            return None
    
    def _parse_flexible_group(self, group, last_sequence=0):
        """🔥 新增：灵活解析字段组为市场数据（支持7字段或8字段，自动补充序号）"""
        try:
            group_len = len(group)
            texts = [self._clean_text(item['text']) for item in group]
            
            if group_len == 8:
                # 8字段格式：序号 + 代码 + 名称 + 仓位 + 成本 + 最新 + 盈亏 + 状态
                return {
                    '序号': texts[0],
                    '代码': texts[1],
                    '名称': texts[2],
                    '仓位比例': texts[3],
                    '成本价': texts[4],
                    '最新价': texts[5],
                    '盈亏比例': texts[6],
                    '状态': texts[7]
                }
            elif group_len == 7:
                # 🔥 7字段格式（缺序号）：代码 + 名称 + 仓位 + 成本 + 最新 + 盈亏 + 状态
                # 自动补充序号：如果是第一条数据，序号为1，否则为前面数据的序号+1
                auto_sequence = str(last_sequence + 1)
                self.logger.info(f"🔢 7字段数据自动补充序号: {auto_sequence} (上一个序号: {last_sequence})")
                
                return {
                    '序号': auto_sequence,  # 🔥 自动补充序号
                    '代码': texts[0],
                    '名称': texts[1],
                    '仓位比例': texts[2],
                    '成本价': texts[3],
                    '最新价': texts[4],
                    '盈亏比例': texts[5],
                    '状态': texts[6]
                }
            else:
                self.logger.error(f"不支持的字段组长度: {group_len}")
                return None
            
        except Exception as e:
            self.logger.error(f"解析灵活字段组失败: {e}")
            return None
    
    def _is_sequence_field(self, text, last_sequence):
        """验证是否为序号字段：纯数字（放宽连续性要求，避免数据丢失）"""
        if not text:
            self.logger.debug(f"序号字段为空: '{text}'")
            return False
        
        text = text.strip()
        if not text.isdigit():
            self.logger.debug(f"序号字段不是纯数字: '{text}'")
            return False
        
        try:
            current_sequence = int(text)
            
            # 如果是第一条数据（last_sequence为None），接受任意起始序号
            if last_sequence is None:
                self.logger.debug(f"序号验证: 第一条数据，接受起始序号={current_sequence}")
                return True
            
            # 放宽验证：只要是数字且大于等于上一个序号就接受
            # 这样可以处理OCR识别顺序不对或跳号的情况
            result = current_sequence >= last_sequence
            if result:
                self.logger.debug(f"序号验证通过: 当前={current_sequence}, 上一个={last_sequence}")
            else:
                self.logger.debug(f"序号验证: 当前={current_sequence} < 上一个={last_sequence}, 可能是OCR识别错误")
                # 即使序号不连续，只要是数字就接受（进一步放宽）
                result = True
                
            return result
        except Exception as e:
            self.logger.debug(f"序号字段转换失败: '{text}', 错误: {e}")
            return False
    
    def _validate_8_field_row_relaxed(self, columns, last_sequence):
        """宽松验证8字段行数据（减少数据丢失）"""
        try:
            if len(columns) != 8:
                self.logger.warning(f"❌ 字段行长度不正确: {len(columns)} != 8")
                return False
            
            # 获取文本内容
            texts = [col.get('text', '').strip() for col in columns]
            self.logger.info(f"🔍 宽松验证8字段行: {texts}")
            
            # 最基本的验证：
            # 1. 第1个字段应该像序号（纯数字）
            field1_ok = texts[0] and texts[0].isdigit()
            
            # 2. 第2个字段应该像股票代码（包含字母数字）
            field2_ok = texts[1] and any(c.isalnum() for c in texts[1])
            
            # 3. 第3个字段应该是名称（不为空）
            field3_ok = texts[2].strip() != ""
            
            # 4. 第4个字段应该像仓位比例（包含%或者是数字）
            field4_ok = texts[3] and ('%' in texts[3] or any(c.isdigit() for c in texts[3]))
            
            # 只要前4个字段看起来合理就接受
            result = field1_ok and field2_ok and field3_ok and field4_ok
            
            if result:
                self.logger.info(f"✅ 宽松验证通过: 序号={texts[0]}, 代码={texts[1]}, 名称={texts[2]}, 仓位={texts[3]}")
            else:
                self.logger.warning(f"❌ 宽松验证失败: 序号OK={field1_ok}, 代码OK={field2_ok}, 名称OK={field3_ok}, 仓位OK={field4_ok}")
            
            return result
            
        except Exception as e:
            self.logger.warning(f"宽松验证异常: {e}")
            return False
    
    def _validate_8_field_group_relaxed(self, group, last_sequence):
        """宽松验证8字段组数据（原始文本解析方式）"""
        try:
            if len(group) != 8:
                self.logger.warning(f"❌ 字段组长度不正确: {len(group)} != 8")
                return False
            
            # 获取文本内容
            texts = [item['text'].strip() for item in group]
            self.logger.info(f"🔍 宽松验证8字段组: {texts}")
            
            # 最基本的验证：
            # 1. 第1个字段应该像序号（纯数字）
            field1_ok = texts[0] and texts[0].isdigit()
            
            # 2. 第2个字段应该像股票代码（包含字母数字）
            field2_ok = texts[1] and any(c.isalnum() for c in texts[1])
            
            # 3. 第3个字段应该是名称（不为空）
            field3_ok = texts[2].strip() != ""
            
            # 4. 第4个字段应该像仓位比例（包含%或者是数字）
            field4_ok = texts[3] and ('%' in texts[3] or any(c.isdigit() for c in texts[3]))
            
            # 只要前4个字段看起来合理就接受
            result = field1_ok and field2_ok and field3_ok and field4_ok
            
            if result:
                self.logger.info(f"✅ 宽松验证通过: 序号={texts[0]}, 代码={texts[1]}, 名称={texts[2]}, 仓位={texts[3]}")
            else:
                self.logger.warning(f"❌ 宽松验证失败: 序号OK={field1_ok}, 代码OK={field2_ok}, 名称OK={field3_ok}, 仓位OK={field4_ok}")
            
            return result
            
        except Exception as e:
            self.logger.warning(f"宽松验证异常: {e}")
            return False
    
    def _validate_flexible_group(self, group):
        """🔥 新增：灵活验证字段组数据（支持7字段或8字段）"""
        try:
            group_len = len(group)
            if group_len not in [7, 8]:
                self.logger.warning(f"❌ 字段组长度不支持: {group_len} (支持7或8字段)")
                return False
            
            # 获取文本内容
            texts = [item['text'].strip() for item in group]
            self.logger.info(f"🔍 灵活验证{group_len}字段组: {texts}")
            
            if group_len == 8:
                # 8字段格式：序号 + 代码 + 名称 + 仓位 + 成本 + 最新 + 盈亏 + 状态
                # 1. 第1个字段应该像序号（纯数字）
                field1_ok = texts[0] and texts[0].isdigit()
                # 2. 第2个字段应该像股票代码（包含字母数字）
                field2_ok = texts[1] and any(c.isalnum() for c in texts[1])
                # 3. 第3个字段应该是名称（不为空）
                field3_ok = texts[2].strip() != ""
                # 4. 第4个字段应该像仓位比例（包含%）
                field4_ok = texts[3] and '%' in texts[3]
                
                result = field1_ok and field2_ok and field3_ok and field4_ok
                
                if result:
                    self.logger.info(f"✅ 8字段验证通过: 序号={texts[0]}, 代码={texts[1]}, 名称={texts[2]}, 仓位={texts[3]}")
                else:
                    self.logger.warning(f"❌ 8字段验证失败: 序号OK={field1_ok}, 代码OK={field2_ok}, 名称OK={field3_ok}, 仓位OK={field4_ok}")
                
            else:  # group_len == 7
                # 🔥 7字段格式有两种情况：
                # 情况1：缺序号 - 代码 + 名称 + 仓位 + 成本 + 最新 + 盈亏 + 状态
                # 情况2：第1字段不是数字 - 可能是缺失的序号，需要补充
                
                # 检查第1个字段是否像股票代码
                field1_is_code = texts[0] and any(c.isalnum() for c in texts[0])
                field2_is_name = texts[1].strip() != ""
                field3_is_position = texts[2] and '%' in texts[2]
                
                # 如果前3个字段都符合"代码+名称+仓位"的特征，那就是缺序号的7字段格式
                if field1_is_code and field2_is_name and field3_is_position:
                    result = True
                    self.logger.info(f"✅ 7字段验证通过(缺序号): 代码={texts[0]}, 名称={texts[1]}, 仓位={texts[2]}")
                else:
                    # 可能第1个字段不是有效的股票代码，尝试其他验证
                    result = False
                    self.logger.warning(f"❌ 7字段验证失败: 代码OK={field1_is_code}, 名称OK={field2_is_name}, 仓位OK={field3_is_position}")
            
            return result
            
        except Exception as e:
            self.logger.warning(f"灵活验证异常: {e}")
            return False
    
    def _is_code_field(self, text):
        """验证是否为代码字段：只包含字母和数字"""
        if not text:
            return False
        text = text.strip()
        return text.isalnum() and len(text) >= 2
    
    def _is_position_ratio_field(self, text):
        """验证是否为仓位比例字段：百分比且不超过100%"""
        if not text or '%' not in text:
            return False
        
        try:
            # 提取数字部分
            number_str = text.replace('%', '').replace('+', '').replace('-', '').strip()
            number = float(number_str)
            return 0 <= number <= 100
        except:
            return False
    
    def _is_cost_price_field(self, text):
        """验证是否为成本价字段：纯数字，有负数，有小数"""
        if not text:
            self.logger.debug(f"成本价字段为空: '{text}'")
            return False
        
        try:
            # 可能包含负号和小数点
            text = text.strip()
            if text.startswith('+'):
                text = text[1:]
            
            float(text)  # 能转换为浮点数
            has_decimal_or_negative = '.' in text or '-' in text
            self.logger.debug(f"成本价字段验证: '{text}', 有小数点或负号: {has_decimal_or_negative}")
            return has_decimal_or_negative  # 包含小数点或负号
        except Exception as e:
            self.logger.debug(f"成本价字段转换失败: '{text}', 错误: {e}")
            return False
    
    def _is_current_price_field(self, text):
        """验证是否为最新价字段：纯数字，无负数，有小数"""
        if not text:
            self.logger.debug(f"最新价字段为空: '{text}'")
            return False
        
        try:
            text = text.strip()
            if text.startswith('-'):  # 不能是负数
                self.logger.debug(f"最新价字段不能为负数: '{text}'")
                return False
            
            if text.startswith('+'):
                text = text[1:]
            
            number = float(text)
            has_decimal = '.' in text
            is_non_negative = number >= 0
            result = is_non_negative and has_decimal
            self.logger.debug(f"最新价字段验证: '{text}', 非负数: {is_non_negative}, 有小数点: {has_decimal}, 结果: {result}")
            return result  # 非负数且包含小数点
        except Exception as e:
            self.logger.debug(f"最新价字段转换失败: '{text}', 错误: {e}")
            return False
    
    def _is_profit_loss_field(self, text):
        """验证是否为盈亏比例字段：百分比，有负数有小数"""
        if not text or '%' not in text:
            self.logger.debug(f"盈亏比例字段无百分号: '{text}'")
            return False
        
        try:
            # 提取数字部分（保留符号）
            number_str = text.replace('%', '').strip()
            float(number_str)  # 能转换为浮点数
            has_decimal = '.' in number_str
            self.logger.debug(f"盈亏比例字段验证: '{text}', 数字部分: '{number_str}', 有小数点: {has_decimal}")
            return has_decimal  # 包含小数点
        except Exception as e:
            self.logger.debug(f"盈亏比例字段转换失败: '{text}', 错误: {e}")
            return False
    
    def _is_status_field(self, text):
        """验证是否为状态字段：纯汉字"""
        if not text:
            self.logger.debug(f"状态字段为空: '{text}'")
            return False
        
        text = text.strip()
        # 检查是否全部为汉字
        all_chinese = all('\u4e00' <= c <= '\u9fff' for c in text)
        long_enough = len(text) >= 2
        result = all_chinese and long_enough
        self.logger.debug(f"状态字段验证: '{text}', 全部中文: {all_chinese}, 长度>=2: {long_enough}, 结果: {result}")
        return result
    
    def _is_valid_ocr_text(self, text: str) -> bool:
        """判断OCR识别的文本是否有效"""
        if not text:
            return False
        
        text = text.strip()
        
        # 过滤单个无效字符
        invalid_single_chars = {'O', 'o', '0', 'l', 'I', '|', '_', '-', '–'}
        if len(text) == 1 and text in invalid_single_chars:
            self.logger.debug(f"过滤无效单字符: '{text}'")
            return False
        
        # 过滤只包含特殊字符的文本
        if not any(c.isalnum() or '\u4e00' <= c <= '\u9fff' for c in text):
            return False
        
        return True
    
    def _clean_text(self, text: str) -> str:
        """清理文本内容，去除无效字符"""
        if not text:
            return ''
        
        # 去除首尾空白
        text = text.strip()
        
        # 去除一些OCR常见的错误字符
        text = text.replace('|', '').replace('_', '').replace('–', '-')
        
        # 如果文本只包含特殊字符或长度小于1，返回空字符串
        if not text or len(text.strip()) < 1:
            return ''
        
        return text
    
    def select_area(self):
        """框选识别区域"""
        try:
            dialog = AreaSelectorDialog()
            area = dialog.select_area()
            
            if area:
                # 直接保存区域配置，不需要命名
                area_str = f"{area[0]},{area[1]},{area[2]},{area[3]}"
                self.config_manager.set('area.current_area', area_str)
                self.config_manager.set('area.bbox', area)
                
                # 更新状态显示
                self.area_status_label.setText(f"已设置区域: ({area[2]-area[0]}×{area[3]-area[1]})")
                self.area_status_label.setStyleSheet("color: #006600;")
                
                # 启用预览按钮
                self.preview_btn.setEnabled(True)
                
                # 记录操作
                self.add_history_record("框选区域", f"设置识别区域: {area[2]-area[0]}×{area[3]-area[1]}", "success")
                
                # 保存配置
                self.config_manager.auto_save()
                
                # 发送区域变更信号
                self.config_changed.emit('area.current_area', area_str)
                
                self.logger.info(f"设置识别区域: {area}")
        
        except Exception as e:
            self.logger.error(f"框选区域失败: {e}")
            self.add_history_record("框选区域", f"失败: {e}", "error")
    
    def preview_area(self):
        """预览识别区域"""
        try:
            area = self.config_manager.get('area.bbox')
            if not area:
                QMessageBox.information(self, "提示", "请先框选识别区域")
                return
            
            # 使用OCR服务截图
            from ocr.ocr_service import OCRService
            ocr_service = OCRService()
            
            img_path = ocr_service.take_screenshot(bbox=area)
            if img_path:
                # 显示预览窗口
                self.show_preview_window(img_path)
                self.add_history_record("预览区域", "查看识别区域截图", "success")
            else:
                QMessageBox.warning(self, "错误", "截图失败")
                
        except Exception as e:
            self.logger.error(f"预览区域失败: {e}")
            QMessageBox.critical(self, "错误", f"预览失败: {e}")
    
    def show_preview_window(self, img_path):
        """显示预览窗口"""
        try:
            from PyQt5.QtWidgets import QDialog, QLabel, QVBoxLayout
            from PyQt5.QtGui import QPixmap
            from PyQt5.QtCore import Qt
            
            dialog = QDialog(self)
            dialog.setWindowTitle("区域预览")
            dialog.setModal(True)
            
            layout = QVBoxLayout(dialog)
            
            # 显示图片
            label = QLabel()
            pixmap = QPixmap(img_path)
            
            # 调整图片大小以适应屏幕
            screen_size = dialog.screen().size()
            max_width = int(screen_size.width() * 0.8)
            max_height = int(screen_size.height() * 0.8)
            
            if pixmap.width() > max_width or pixmap.height() > max_height:
                pixmap = pixmap.scaled(max_width, max_height, Qt.KeepAspectRatio, Qt.SmoothTransformation)
            
            label.setPixmap(pixmap)
            label.setAlignment(Qt.AlignCenter)
            layout.addWidget(label)
            
            # 添加说明
            info_label = QLabel(f"区域大小: {pixmap.width()} × {pixmap.height()}")
            info_label.setAlignment(Qt.AlignCenter)
            info_label.setStyleSheet("color: #666666; padding: 10px;")
            layout.addWidget(info_label)
            
            dialog.resize(pixmap.width() + 40, pixmap.height() + 80)
            dialog.exec_()
            
            # 清理临时文件
            import os
            if os.path.exists(img_path):
                os.remove(img_path)
                
        except Exception as e:
            self.logger.error(f"显示预览窗口失败: {e}")
    
    def on_area_changed(self, area_str):
        """区域设置改变"""
        if area_str:
            self.config_changed.emit('area.current_area', area_str)
    

    
    def on_config_changed(self):
        """配置变更处理"""
        # 保存配置到管理器
        self.save_current_config()
        
        # 发送配置变更信号
        self.config_changed.emit('config', 'updated')
    
    def save_current_config(self):
        """保存当前配置"""
        try:
            # 保存交易配置（不保存密码）
            self.config_manager.set('trading.auto_trade', self.auto_trade_cb.isChecked())
            self.config_manager.set('trading.buy_price_offset', self.buy_price_offset_spin.value())
            self.config_manager.set('trading.sell_price_offset', self.sell_price_offset_spin.value())
            
            # 保存当前选中的券商和账户
            current_broker = self.get_current_broker()
            if current_broker:
                self.config_manager.set('trading.selected_broker', current_broker)
                
            current_acc_id = self.get_current_acc_id()
            if current_acc_id:
                self.config_manager.set('trading.selected_acc_id', current_acc_id)
            
            # 保存运行时长配置
            self.config_manager.set('monitor.runtime_minutes', self.runtime_spin.value())
            
            # 自动保存
            self.config_manager.auto_save()
            
        except Exception as e:
            self.logger.error(f"保存配置失败: {e}")
    
    def start_monitoring_clicked(self):
        """开始监控"""
        # 验证配置
        current_area = self.config_manager.get('area.current_area')
        if not current_area:
            QMessageBox.warning(self, "配置错误", "请先框选识别区域")
            return
        
        if not self.password_edit.text().strip():
            QMessageBox.warning(self, "配置错误", "请设置交易密码后再开始监控")
            return
        
        # 更新状态
        self.is_monitoring = True
        self.start_btn.setEnabled(False)
        self.stop_btn.setEnabled(True)
        
        # 保存配置
        self.save_current_config()
        
        # 记录操作
        self.add_history_record("启动监控", "开始监控股票信号", "success")
        
        # 🔥 开始监控时清空数据库并获取持仓基准
        self._initialize_position_baseline()
        
        # 启动账户资金实时监控
        self.start_account_monitoring()
        
        # 发送信号
        self.start_monitoring.emit()
    
    def stop_monitoring_clicked(self):
        """停止监控"""
        self.is_monitoring = False
        self.start_btn.setEnabled(True)
        self.stop_btn.setEnabled(False)
        
        # 记录操作
        self.add_history_record("停止监控", "监控已停止", "success")
        
        # 停止账户资金实时监控
        self.stop_account_monitoring()
        
        # 发送信号
        self.stop_monitoring.emit()
    
    def test_ocr(self):
        """测试OCR功能 - 将识别结果打印到日志区域"""
        area = self.config_manager.get('area.bbox')
        if not area:
            QMessageBox.information(self, "提示", "请先框选识别区域")
            return
        
        try:
            # 使用OCR服务进行测试
            from ocr.ocr_service import OCRService
            ocr_service = OCRService()
            
            if not ocr_service.ensure_service_running():
                QMessageBox.warning(self, "错误", "OCR服务未启动")
                return
            
            # 记录开始测试
            self.logger.info("=" * 50)
            self.logger.info("🔍 开始测试OCR识别")
            area_size = f"{area[2]-area[0]}×{area[3]-area[1]}"
            self.logger.info(f"识别区域: {area_size} 像素")
            
            result = ocr_service.ocr_area(area)
            if result:
                text_count = len(result)
                self.logger.info(f"✅ OCR识别成功！识别到 {text_count} 个文本区域")
                self.logger.info("-" * 30)
                
                # 逐个打印识别结果到日志
                for i, (key, value) in enumerate(result.items(), 1):
                    text = value.get('rec_txt', '').strip()
                    score = value.get('score', 0)
                    bbox = value.get('dt_boxes', [])
                    
                    if text:  # 只显示有文本内容的
                        
                        if bbox and len(bbox) >= 4:
                            # 计算位置信息
                            x_coords = [point[0] for point in bbox]
                            y_coords = [point[1] for point in bbox]
                            center_x = int(sum(x_coords) / len(x_coords))
                            center_y = int(sum(y_coords) / len(y_coords))
                            self.logger.info(f"        位置: ({center_x}, {center_y})")
                
                self.logger.info("-" * 30)
                self.add_history_record("测试OCR", f"识别成功，找到 {text_count} 个文本", "success")
            else:
                self.logger.warning("❌ OCR测试失败，未识别到文本内容")
                self.add_history_record("测试OCR", "识别失败", "error")
                
            # 同时更新市场数据表格
            if result:
                # 构建包含enhanced_data的完整结构
                enhanced_result = {
                    'enhanced_data': ocr_service.extract_structured_data(result)
                }
                # 同时包含原始数据作为fallback
                enhanced_result.update(result)
                self.update_market_data(enhanced_result)
                
            self.logger.info("🔍 OCR测试完成")
            self.logger.info("=" * 50)
                
        except Exception as e:
            self.logger.error(f"❌ OCR测试异常: {e}")
            self.add_history_record("测试OCR", f"失败: {e}", "error")
    
    def show_trading_history(self):
        """显示交易历史弹窗"""
        try:
            from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, 
                                       QTableWidget, QTableWidgetItem, QHeaderView,
                                       QPushButton, QLabel)
            
            dialog = QDialog(self)
            dialog.setWindowTitle("交易历史")
            dialog.setModal(True)
            dialog.resize(1200, 500)  # 增加窗口宽度以容纳更多列
            
            layout = QVBoxLayout(dialog)
            
            # 标题
            title_layout = QHBoxLayout()
            title_layout.addWidget(QLabel("交易历史记录"))
            
            # 清空按钮
            clear_btn = QPushButton("清空历史")
            clear_btn.clicked.connect(lambda: self.clear_trading_history(dialog))
            title_layout.addWidget(clear_btn)
            
            title_layout.addStretch()
            layout.addLayout(title_layout)
            
            # 交易历史表格 - 按照用户要求的详细字段设计
            history_table = QTableWidget()
            history_table.setColumnCount(11)
            history_table.setHorizontalHeaderLabels([
                "股票代码", "交易方向", "数量", "金额", "变化前仓位", 
                "当前仓位", "仓位差距", "账户资金", "状态", "记录时间", "操作时间"
            ])
            
            # 设置表格样式 - 启用横向滚动条，列宽可手动调整
            header = history_table.horizontalHeader()
            header.setSectionResizeMode(QHeaderView.Interactive)  # 允许手动调整列宽
            header.setStretchLastSection(False)  # 最后一列不自动拉伸
            
            # 设置列的初始宽度
            column_widths = [80, 60, 60, 80, 80, 80, 80, 100, 80, 130, 130]
            for i, width in enumerate(column_widths):
                history_table.setColumnWidth(i, width)
            
            history_table.setAlternatingRowColors(True)
            history_table.setSelectionBehavior(QTableWidget.SelectRows)
            
            # 加载交易历史数据
            self.load_trading_history_to_table(history_table)
            
            layout.addWidget(history_table)
            
            # 关闭按钮
            close_btn = QPushButton("关闭")
            close_btn.clicked.connect(dialog.close)
            close_layout = QHBoxLayout()
            close_layout.addStretch()
            close_layout.addWidget(close_btn)
            layout.addLayout(close_layout)
            
            dialog.exec_()
            
        except Exception as e:
            self.logger.error(f"显示交易历史失败: {e}")
    
    def load_trading_history_to_table(self, table):
        """加载交易历史到表格"""
        try:
            from PyQt5.QtWidgets import QTableWidgetItem
            from datetime import datetime
            
            # 🔥 修复：获取当前账户的货币信息用于显示正确单位
            current_currency_symbol = "$"
            current_currency_suffix = "USD"
            try:
                current_account = self.account_combo.currentData()
                if current_account:
                    broker_name = current_account.get('broker_name', '')
                    if 'FUTU HK' in broker_name or 'HK' in broker_name:
                        current_currency_symbol = "HK$"
                        current_currency_suffix = "HKD"
                    else:
                        current_currency_symbol = "$"
                        current_currency_suffix = "USD"
                    
                    self.logger.debug(f"🔍 交易历史货币显示: 券商={broker_name}, 符号={current_currency_symbol}")
            except Exception as e:
                self.logger.warning(f"获取当前账户货币信息失败，使用默认美元显示: {e}")
            
            # 获取详细交易记录（新的记录系统）
            trading_records = self.config_manager.get_trading_records()
            
            table.setRowCount(len(trading_records))
            
            for row, record in enumerate(trading_records):
                # 提取记录数据
                stock_code = record.get('stock_code', '')
                direction = record.get('direction', '')
                quantity = record.get('quantity', 0)
                amount = record.get('amount', 0.0)
                prev_position = record.get('prev_position', 0.0)
                current_position = record.get('current_position', 0.0)
                position_diff = record.get('position_diff', 0.0)
                account_funds = record.get('account_funds', 0.0)
                ocr_status = record.get('ocr_status', '')
                record_time = record.get('record_time', '')
                operation_time = record.get('operation_time', '')
                
                # 格式化时间
                def format_time(time_str):
                    if not time_str:
                        return ""
                    try:
                        dt = datetime.fromisoformat(time_str)
                        return dt.strftime('%m-%d %H:%M:%S')
                    except:
                        return time_str[:16] if len(time_str) > 16 else time_str
                
                formatted_record_time = format_time(record_time)
                formatted_operation_time = format_time(operation_time) if operation_time else "未执行"
                
                # 设置表格数据
                table.setItem(row, 0, QTableWidgetItem(stock_code))
                # 将"买入/卖出"简化为"买/卖"
                simplified_direction = "买" if direction == "买入" else "卖" if direction == "卖出" else direction
                table.setItem(row, 1, QTableWidgetItem(simplified_direction))
                table.setItem(row, 2, QTableWidgetItem(str(quantity)))
                table.setItem(row, 3, QTableWidgetItem(f"{current_currency_symbol}{amount:,.2f}"))
                table.setItem(row, 4, QTableWidgetItem(f"{prev_position:.2f}%"))
                table.setItem(row, 5, QTableWidgetItem(f"{current_position:.2f}%"))
                table.setItem(row, 6, QTableWidgetItem(f"{position_diff:+.2f}%"))
                table.setItem(row, 7, QTableWidgetItem(f"{current_currency_symbol}{account_funds:,.0f}"))
                table.setItem(row, 8, QTableWidgetItem(ocr_status))
                table.setItem(row, 9, QTableWidgetItem(formatted_record_time))
                table.setItem(row, 10, QTableWidgetItem(formatted_operation_time))
                
                # 设置行颜色：根据是否已执行和交易方向
                for col in range(11):
                    item = table.item(row, col)
                    if item:
                        if operation_time:  # 已执行的交易
                            if direction == "买入":
                                item.setForeground(Qt.darkGreen)  # 买入用绿色
                            else:  # 卖出
                                item.setForeground(Qt.darkRed)    # 卖出用红色
                        else:  # 未执行的交易
                            item.setForeground(Qt.gray)           # 待执行用灰色
            
        except Exception as e:
            self.logger.error(f"加载交易历史失败: {e}")
    
    def clear_trading_history(self, dialog):
        """清空交易历史"""
        from PyQt5.QtWidgets import QTableWidget
        
        reply = QMessageBox.question(
            dialog, '确认清空', '确定要清空所有交易历史和数据库基准数据吗？',
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            # 清空详细交易记录
            self.config_manager.set('trading.records', [])
            
            # 🔥 清空配置文件中的历史市场数据（确保完全清理）
            self.config_manager.set('market.previous_data', [])
            self.config_manager.auto_save()
            
            # 🔥 清空数据库历史数据
            self.clear_database_history()
            
            # 重新加载表格
            table = dialog.findChild(QTableWidget)
            if table:
                self.load_trading_history_to_table(table)
            
            self.logger.info("交易历史和数据库基准数据已清空")
    
    def refresh_market_data(self):
        """刷新市场数据"""
        try:
            area = self.config_manager.get('area.bbox')
            if not area:
                QMessageBox.information(self, "提示", "请先框选识别区域")
                return
            
            # 执行OCR识别并更新市场数据
            from ocr.ocr_service import OCRService
            ocr_service = OCRService()
            
            if not ocr_service.ensure_service_running():
                QMessageBox.warning(self, "错误", "OCR服务未启动")
                return
            
            self.logger.info("🔄 刷新市场数据...")
            result = ocr_service.ocr_area(area)
            
            if result:
                self.update_market_data(result)
                self.add_history_record("刷新市场", "市场数据已更新", "success")
            else:
                self.logger.warning("⚠️ 未识别到市场数据")
                # 如果没有识别到数据，清空当前数据
                if hasattr(self, 'market_data_list'):
                    self.market_data_list.clear()
                    self.refresh_market_table()
                
        except Exception as e:
            self.logger.error(f"刷新市场数据失败: {e}")
            QMessageBox.critical(self, "错误", f"刷新失败: {e}")
    
    def clear_market_data(self):
        """清空当前市场数据"""
        try:
            reply = QMessageBox.question(
                self, '确认清空', '确定要清空当前市场列表吗？',
                QMessageBox.Yes | QMessageBox.No
            )
            
            if reply == QMessageBox.Yes:
                # 清空市场数据
                if hasattr(self, 'market_data_list'):
                    self.market_data_list.clear()
                
                # 清空表格显示
                self.market_table.setRowCount(0)
                
                self.logger.info("🗑️ 当前市场列表已清空")
                self.add_history_record("清空市场", "当前市场列表已清空", "success")
                
        except Exception as e:
            self.logger.error(f"清空市场数据失败: {e}")
            QMessageBox.critical(self, "错误", f"清空失败: {e}")
    
    def on_always_on_top_changed(self, checked):
        """窗口置顶状态改变"""
        try:
            self.always_on_top_changed.emit(checked)
            if checked:
                self.logger.info("✅ 窗口置顶已启用")
            else:
                self.logger.info("❌ 窗口置顶已禁用")
        except Exception as e:
            self.logger.error(f"窗口置顶状态变更失败: {e}")
    
    def add_history_record(self, action: str, details: str, status: str = "info"):
        """添加操作记录"""
        # 添加到配置管理器
        self.config_manager.add_history_record(action, details, status)
    
    def get_current_config(self):
        """获取当前配置"""
        return {
            'current_area': self.config_manager.get('area.current_area'),
            'auto_trade': self.auto_trade_cb.isChecked(),
            'runtime_minutes': self.runtime_spin.value(),
            'selected_broker': self.get_current_broker(),
            'selected_acc_id': self.get_current_acc_id()
        }
    
    def refresh_accounts(self):
        """刷新当前选中券商的账户列表"""
        try:
            self.logger.info("🔄 刷新账户列表...")
            
            # 获取当前选中的券商
            current_broker_data = self.broker_combo.currentData()
            if not current_broker_data:
                self.account_combo.clear()
                self.account_combo.addItem("请先选择券商", None)
                self.update_account_info(None)
                return
            
            # 获取该券商的账户列表
            accounts = current_broker_data.get('accounts', [])
            
            # 清空当前下拉框
            self.account_combo.clear()
            
            if not accounts:
                self.account_combo.addItem("该券商暂无可用账户", None)
                self.update_account_info(None)
                self.logger.warning(f"⚠️ 券商 {current_broker_data.get('broker_name', '')} 暂无可用账户")
                return
            
            # 添加账户到下拉框
            for account in accounts:
                # 新的显示格式：卡号 - 市场 - 账户类型 - 总资产(对应货币)
                total_assets = account.get('total_assets', 0)
                market = account.get('market', '')
                currency = account.get('currency', 'USD')
                
                # 🔥 修复：根据broker_name和currency正确判断单位
                broker_name = account.get('broker_name', '')
                
                if currency == 'USD' or broker_name == 'Moomoo US':
                    currency_symbol = '$'
                    currency_suffix = 'USD'
                elif currency == 'HKD' or broker_name == 'FUTU HK':
                    currency_symbol = 'HK$' 
                    currency_suffix = 'HKD'
                else:
                    # 默认根据currency字段判断
                    if currency == 'USD':
                        currency_symbol = '$'
                        currency_suffix = 'USD'
                    else:
                        currency_symbol = 'HK$'
                        currency_suffix = 'HKD'
                
                display_name = f"{account['uni_card_num']} - {market} - {account['acc_type']} - {currency_symbol}{total_assets:,.0f} {currency_suffix}"
                self.account_combo.addItem(display_name, account)
            
            # 如果有账户，选择第一个
            if accounts:
                self.account_combo.setCurrentIndex(0)
                self.update_account_info(accounts[0])
            
            self.logger.info(f"✅ 已加载券商 {current_broker_data.get('broker_name', '')} 的 {len(accounts)} 个可用账户")
            
        except Exception as e:
            self.logger.error(f"刷新账户列表失败: {e}")
            # 设置错误状态的下拉框
            self.account_combo.clear()
            self.account_combo.addItem(f"获取账户失败: {str(e)[:50]}...", None)
            self.update_account_info(None)
    
    def on_account_changed(self):
        """账户选择变更事件"""
        try:
            current_data = self.account_combo.currentData()
            self.update_account_info(current_data)
            
            if current_data:
                # 清空交易密码（不同账户有不同密码）
                self.password_edit.setText('')
                self.logger.info(f"📊 切换到账户: {current_data['uni_card_num']}，请输入该账户对应的交易密码")
                self.on_config_changed()  # 触发配置保存
                
                # 🔥 重要：账户变更后，重新初始化持仓基准数据
                if self.market_db:
                    self.logger.info("🔄 账户切换，重新初始化持仓基准数据...")
                    # 清空当前基准数据
                    self.market_db.clear_baseline_data()
                    # 重新获取持仓数据作为基准
                    self._initialize_position_baseline()
            
        except Exception as e:
            self.logger.error(f"账户切换失败: {e}")
    
    def update_account_info(self, account_data):
        """更新账户信息显示"""
        try:
            if not account_data:
                self.account_funds_label.setText("--")
                self.funds_update_time_label.setText("--")
                return
            
            # 显示账户资金（根据货币类型正确显示）+ acc_id
            total_assets = account_data.get('total_assets', 0)
            acc_id = account_data.get('acc_id', 'N/A')
            
            # 🔥 使用标准化的货币显示逻辑
            currency = account_data.get('currency', 'USD')
            
            if currency == 'USD':
                # 美元账户显示
                self.account_funds_label.setText(f"${total_assets:,.2f} USD (ID: {acc_id})")
                
                # 如果有汇率转换信息，记录日志
                conversion_rate = account_data.get('conversion_rate', 1.0)
                if conversion_rate != 1.0:
                    original_hkd = account_data.get('original_hkd_assets', 0)
                    self.logger.info(f"💱 账户信息显示: ${total_assets:,.2f} USD (原始: HK${original_hkd:,.2f}, 汇率: {conversion_rate:.4f})")
            else:
                # 港币账户显示
                self.account_funds_label.setText(f"HK${total_assets:,.2f} HKD (ID: {acc_id})")
                self.logger.info(f"💰 账户信息显示: HK${total_assets:,.2f}")
            
            # 显示更新时间（如果有的话）
            if self.last_funds_update_time:
                self.funds_update_time_label.setText(f"更新: {self.last_funds_update_time}")
            else:
                self.funds_update_time_label.setText("--")
            
        except Exception as e:
            self.logger.error(f"更新账户信息失败: {e}")
    
    def get_current_acc_id(self):
        """获取当前选中的账户ID"""
        try:
            current_data = self.account_combo.currentData()
            if current_data:
                return current_data.get('acc_id', '')
            return ''
        except Exception as e:
            self.logger.error(f"获取当前账户ID失败: {e}")
            return ''
    
    def select_account_by_acc_id(self, acc_id):
        """根据acc_id选择账户"""
        try:
            for i in range(self.account_combo.count()):
                account_data = self.account_combo.itemData(i)
                if account_data and account_data.get('acc_id') == acc_id:
                    self.account_combo.setCurrentIndex(i)
                    self.logger.info(f"✅ 已选择账户: {acc_id}")
                    return True
            
            self.logger.warning(f"⚠️ 未找到账户: {acc_id}")
            return False
            
        except Exception as e:
            self.logger.error(f"选择账户失败: {e}")
            return False
    
    def get_current_account_funds(self):
        """获取当前账户的总资产（用于交易计算）"""
        try:
            current_data = self.account_combo.currentData()
            if current_data:
                return current_data.get('total_assets', 0.0)
            return 0.0
        except Exception as e:
            self.logger.error(f"获取当前账户资金失败: {e}")
            return 0.0
    
    def update_current_account_funds(self):
        """实时更新当前选中账户的资金信息"""
        try:
            current_data = self.account_combo.currentData()
            if not current_data:
                return
            
            # 获取当前账户的最新资金信息
            from trading.futu_trader import FutuTrader
            futu_trader = FutuTrader(self.config_manager)
            
            acc_id = current_data.get('acc_id')
            broker_enum = current_data.get('security_firm_enum')
            market_enum = current_data.get('market_enum')
            
            if acc_id and broker_enum and market_enum:
                # 获取最新资金信息
                funds_info = futu_trader.get_account_funds_with_broker(acc_id, broker_enum, market_enum)
                
                if funds_info['total_assets'] > 0:
                    # 🔥 使用新的货币信息来显示资金
                    total_assets = funds_info['total_assets']
                    currency = funds_info.get('currency', 'USD')
                    acc_id = current_data.get('acc_id', 'N/A')
                    
                    # 记录更新时间
                    from datetime import datetime
                    self.last_funds_update_time = datetime.now().strftime("%H:%M:%S")
                    
                    # 根据货币类型显示
                    if currency == 'USD':
                        # 美元显示
                        self.account_funds_label.setText(f"${total_assets:,.2f} USD (ID: {acc_id})")
                        currency_symbol = '$'
                        currency_suffix = 'USD'
                        
                        # 如果有汇率转换信息，记录日志
                        if funds_info.get('conversion_rate', 1.0) != 1.0:
                            original_hkd = funds_info.get('original_hkd_assets', 0)
                            conversion_rate = funds_info.get('conversion_rate', 1.0)
                            self.logger.info(f"💱 美股资金显示: ${total_assets:,.2f} USD (原始: HK${original_hkd:,.2f}, 汇率: {conversion_rate:.4f})")
                    else:
                        # 港币显示
                        self.account_funds_label.setText(f"HK${total_assets:,.2f} HKD (ID: {acc_id})")
                        currency_symbol = 'HK$'
                        currency_suffix = 'HKD'
                        self.logger.info(f"💰 港股资金显示: HK${total_assets:,.2f}")
                    
                    # 更新时间显示
                    self.funds_update_time_label.setText(f"更新: {self.last_funds_update_time}")
                    
                    # 更新下拉框中的数据
                    current_index = self.account_combo.currentIndex()
                    if current_index >= 0:
                        updated_data = current_data.copy()
                        updated_data['total_assets'] = total_assets
                        updated_data['available_funds'] = funds_info['available_funds']
                        updated_data['currency'] = currency  # 更新货币信息
                        
                        # 更新下拉框显示文本
                        market = updated_data.get('market', '')
                        acc_type = updated_data.get('acc_type', '')
                        display_name = f"{updated_data['uni_card_num']} - {market} - {acc_type} - {currency_symbol}{total_assets:,.0f} {currency_suffix}"
                        self.account_combo.setItemText(current_index, display_name)
                        self.account_combo.setItemData(current_index, updated_data)
                    
                    self.logger.debug(f"✅ 账户资金已更新: {acc_id} -> {currency_symbol}{total_assets:,.2f} {currency_suffix}")
                
        except Exception as e:
            self.logger.error(f"实时更新账户资金失败: {e}")
    
    def start_account_monitoring(self):
        """开始账户资金监控"""
        try:
            if not self.account_update_timer.isActive():
                self.account_update_timer.start()
                self.logger.info("✅ 账户资金实时监控已启动 (30秒间隔)")
        except Exception as e:
            self.logger.error(f"启动账户监控失败: {e}")
    
    def stop_account_monitoring(self):
        """停止账户资金监控"""
        try:
            if self.account_update_timer.isActive():
                self.account_update_timer.stop()
                self.logger.info("⏹️ 账户资金实时监控已停止")
        except Exception as e:
            self.logger.error(f"停止账户监控失败: {e}")
    
    def refresh_brokers(self, auto_select_first=True):
        """刷新券商列表
        
        Args:
            auto_select_first (bool): 是否自动选择第一个券商（默认True）
        """
        try:
            self.logger.info("🔄 刷新券商列表...")
            
            # 获取FutuTrader实例
            from trading.futu_trader import FutuTrader
            futu_trader = FutuTrader(self.config_manager)
            
            # 获取用户拥有的券商列表
            brokers = futu_trader.get_available_brokers()
            
            # 清空当前下拉框
            self.broker_combo.clear()
            
            if not brokers:
                self.broker_combo.addItem("暂无可用券商 (请检查OpenD连接)", None)
                self.account_combo.clear()
                self.account_combo.addItem("请先选择券商", None)
                self.update_account_info(None)
                self.logger.warning("⚠️ 未找到可用券商，请检查：1) OpenD是否运行 2) 账户是否为真实且激活状态")
                return
            
            # 添加券商到下拉框
            for broker in brokers:
                broker_name = broker.get('broker_name', 'Unknown')
                account_count = broker.get('account_count', 0)
                display_name = f"{broker_name} ({account_count} 个账户)"
                self.broker_combo.addItem(display_name, broker)
            
            # 🔥 根据参数决定是否自动选择第一个券商
            if brokers and auto_select_first:
                self.broker_combo.setCurrentIndex(0)
                self.refresh_accounts()  # 刷新第一个券商的账户
                self.logger.info("📋 自动选择第一个券商")
            
            self.logger.info(f"✅ 已加载 {len(brokers)} 个可用券商")
            
        except Exception as e:
            self.logger.error(f"刷新券商列表失败: {e}")
            # 设置错误状态的下拉框
            self.broker_combo.clear()
            self.broker_combo.addItem(f"获取券商失败: {str(e)[:50]}...", None)
            self.account_combo.clear()
            self.account_combo.addItem("券商加载失败", None)
            self.update_account_info(None)
    
    def on_broker_changed(self):
        """券商选择变更事件"""
        try:
            # 清空交易密码（不同券商不同账户有不同密码）
            self.password_edit.setText('')
            
            # 当券商改变时，刷新账户列表
            self.refresh_accounts()
            
            # 触发配置保存
            self.on_config_changed()
            
        except Exception as e:
            self.logger.error(f"券商切换失败: {e}")
    
    def get_current_broker(self):
        """获取当前选中的券商名称"""
        try:
            current_data = self.broker_combo.currentData()
            if current_data:
                return current_data.get('broker_name', '')
            return ''
        except Exception as e:
            self.logger.error(f"获取当前券商失败: {e}")
            return ''
    
    def select_broker_by_name(self, broker_name):
        """根据券商名称选择券商"""
        try:
            for i in range(self.broker_combo.count()):
                broker_data = self.broker_combo.itemData(i)
                if broker_data and broker_data.get('broker_name') == broker_name:
                    self.broker_combo.setCurrentIndex(i)
                    return True
            return False
        except Exception as e:
            self.logger.error(f"选择券商失败: {e}")
            return False
